VEH补丁写法,算是对JMP_4E模块的一点补充
本帖最后由 镜中神无 于 2017-3-19 11:24 编辑昨日突发奇想,欲将某开源反汇编器移植到易语言上,奈何工作量太大,手已酸痛不已。忽忆JMP_4E模块,觉其中有反汇编引擎部分,故寻之于赵总,复辗转得之于HOOK4E模块,源码余尚未观之。见JMP_4E模块一缺陷,故前来补充之,饮水当思源。
(在下文言文渣渣,不是什么才子,开头写这一句话只是为了装X,若有文法错误还望诸位指正)
我个人的思路大致是:
1.dll劫持
2.载入我们的dll
(以上两步看参考Nisy大侠的BayMax补丁)
3.写入int3(0xCC)机器码,同时备份原字节
4.安装VEH
5.检测到中断
6.修改寄存器
7.还原原字节,设置线程EFlags寄存器里的TF标志位
8.产生单步异常,还原int3断点
该帖篇幅有限,故只讲3-8步。
在下易语言学艺不精,仅限于刚刚入门语法的水平,不敢前来献丑(连本书都没买,就是一边写程序一边百度,遇到不会的就百度),故用Delphi作为演示。
在下学艺不精,乃是菜鸟一只,如有错误,还望指正,本人不胜感激。
用我写的一个程序做演示。(请到帖子尾部下载)
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib
.data
szText db '你能尝试把我改掉吗?',0
szCaption db '挑衅',0
.code
_RetStr proc
mov eax,offset szText
ret
_RetStr endp
start:
call _RetStr
push 0
push offset szCaption
push eax
push 0
call MessageBox
invoke ExitProcess,0
end start
用OD载入,
00401000/$B8 00304000 MOV EAX, 1.00403000 ;ASCII "你能尝试把我改掉吗?"
00401005\.C3 RETN
00401006 >/$E8 F5FFFFFF CALL 1.00401000
0040100B|.6A 00 PUSH 0x0 ; /Style = MB_OK|MB_APPLMODAL
0040100D|.68 15304000 PUSH 1.00403015 ; |Title = "挑衅"
00401012|.50 PUSH EAX ; |Text
00401013|.6A 00 PUSH 0x0 ; |hOwner = NULL
00401015|.E8 08000000 CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
0040101A|.6A 00 PUSH 0x0 ; /ExitCode = 0x0
0040101C\.E8 07000000 CALL <JMP.&kernel32.ExitProcess> ; \ExitProcess
分析以上,可知,我们只需要把0x401000这个CALL的返回值,即EAX的数值改掉,指向我们自己的字符串内存地址即可。比较简单的方法是,在0x401005上面写入一个INT3断点,触发中断时,我们修改EAX。
下面上代码,为Delphi7编译,Delphi2007测试编译通过,更高版本未测试。学艺不精,如有错误,还望指正。
该例子只考虑了单线程,而未考虑多线程,实际应用中需要注意
library Project1;
uses
SysUtils,
Windows,
Classes;
type
EXCEPTION_POINTERS = record
ExceptionRecord: ^_EXCEPTION_RECORD;
ContextRecord: ^_CONTEXT;
end;
PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
const
EXCEPTION_CONTINUE_EXECUTION = -1;
EXCEPTION_CONTINUE_SEARCH = 0;
pAddress: Pointer = Pointer($401005); //下断地址
var
bOld: Byte;
bInt3: Byte = $CC; //int3机器码
sMyStr: string = '在下已经修改掉了你的内容!';
iState: Boolean = False;
{$R *.res}
function VectoredHandler(ExceptionInfo: PEXCEPTION_POINTERS): Integer; stdcall
begin
case ExceptionInfo.ExceptionRecord.ExceptionCode of
EXCEPTION_BREAKPOINT: //如果是中断异常,就判断是否为我们下了断的地址
begin
if ExceptionInfo.ExceptionRecord.ExceptionAddress = pAddress then
begin
ExceptionInfo.ContextRecord.EFlags := ExceptionInfo.ContextRecord.EFlags or $100; //设置线程EFLAGS寄存器TF标志位
CopyMemory(pAddress, @bOld, 1); //还原原字节
ExceptionInfo.ContextRecord.Eax := Cardinal(PAnsiChar(sMyStr)); //修改EAX寄存器指向我们的字符串地址
iState := True;
Result := EXCEPTION_CONTINUE_EXECUTION; //处理完毕
Exit;
end
else
begin
Result := EXCEPTION_CONTINUE_SEARCH; //未处理
Exit;
end;
end;
EXCEPTION_SINGLE_STEP: //如果是单步异常
begin
if iState then
begin
CopyMemory(pAddress, @bInt3, 1); //重新写下int3断点,在本例子中意义不大 iState := False;
Result := EXCEPTION_CONTINUE_EXECUTION;
end
else
begin
Result := EXCEPTION_CONTINUE_SEARCH;
end;
end;
else
Result := EXCEPTION_CONTINUE_SEARCH;
end;
end;
procedure main();
type
TAddVectoredExceptionHandler = procedure (First: Cardinal; pFunc: Pointer); stdcall;
var
pFunc: TAddVectoredExceptionHandler;
hModule: Cardinal;
iProtect: Cardinal;
begin
hModule := GetModuleHandle('kernel32.dll');
if hModule = 0 then
hModule := LoadLibrary('kernel32.dll');
pFunc := GetProcAddress(hModule, 'AddVectoredExceptionHandler');
pFunc(1, @VectoredHandler); //添加1个异常处理到顶部
VirtualProtect(pAddress, 1, PAGE_EXECUTE_READWRITE, iProtect); //修改代码内存页属性为可写
CopyMemory(@bOld, pAddress, 1); //备份原1Byte机器码,还原时有用
CopyMemory(pAddress, @bInt3, 1); //写入int3断点
end;
exports
main;
begin
main();
end.
如果用LordPE把编译后的dll的main函数导入到程序输入表,打开就会发现这个。
附件下载:
前排 豪华座椅 豪华座椅第二位 新手 看看 学习下 VEH作用于整个进程 和线程有关吗? 谢谢楼主分享,这个思路不错 不會D啊,模糊的好像看懂了思路,可是實在感覺還沒看懂 好文{:5_118:}好文{:5_118:} _BaZzi 发表于 2017-3-19 23:17
VEH作用于整个进程 和线程有关吗?
线程设置tf位单步,特殊情况应该会有多个线程同时触发单步异常的情况。
页:
[1]
2