1 library Project1; //DLL工程文件 2 3 { Important note about DLL memory management: ShareMem must be the 4 first unit in your library's USES clause AND your project's (select 5 Project-View Source) USES clause if your DLL exports any procedures or 6 functions that pass strings as parameters or function results. This 7 applies to all strings passed to and from your DLL--even those that 8 are nested in records and classes. ShareMem is the interface unit to 9 the BORLNDMM.DLL shared memory manager, which must be deployed along 10 with your DLL. To avoid using BORLNDMM.DLL, pass string information 11 using PChar or ShortString parameters. } 12 13 uses 14 System.SysUtils, 15 System.Classes, 16 windows, //为了能使用系统API,必须添加windows单元 17 Vcl.Dialogs; //为了能使用ShowMessage这个信息框,必须添加 18 19 {$R *.res} 20 21 22 var 23 allocaddr:Integer; //定义一个保存申请到的内存空间首地址的变量 24 apiaddr:Integer; //定义一个保存API地址的变量 25 hp:Integer; //定义一个保存进程句柄的变量 26 pid:Integer; //定义一个保存进程PID的变量 27 实际写:NativeUInt; //writeprocessmemory的第5个参数必须为NativeUint类型,否则写入失败 28 写:Integer; //writeprocessmemoty的第4个参数,必须加@,表示取含有数据的变量的地址,为point类型 29 jmps:integer; //jmp的字节码,16进制为E9,十进制为233 30 asmcode:Integer; //将下面的一维静态数据的每个元素数据,strtoint(字符串转数值) 31 code:array [1..16]of string=('60','9C','C6','05','73','19','40','00','74','9D','61','55','8B','EC','6A','FF'); //定义一个从1开始到16,总计16个元素的一维数组,存放str类型的机器码(16进制)
32 function Lens(T, O: Integer): Integer; stdcall; //计算JMP距离的函数,参数T为终点位置,O为起跳位置,从O起跳到T 33 var 34 x: Integer; 35 y: Integer; 36 begin 37 x := T; 38 y := O; 39 Result := x - y - 5; //由于起跳点,比如起跳点为00401000(16进制),实际会占用5个字节{E9(jmp) 1个字节+4个字节的距离},实际起跳位置是00401005,故最终的位置会增加5个距离,所以需要减去, 40 end; //当前函数返回的是10进制,例:如果转成十六进制则需要倒转,比如FFFF01020304,需要倒转为04030201FFFF
62 procedure apihook; stdcall; //此为apihook的过程(过程无返回值) 63 var 64 i: Integer; //定义一个循环变量i,循环把数组的字符串转数值,再写入内存 65 oldpro: Cardinal; //virtualprotectex的第五个参数 66 begin 67 pid := GetCurrentProcessId(); //获取自进程id,dll获取的自进程dll是本Exe的进程ID,因为Delphi中,OpenProcess的第三个参数无法为-1,故用api函数获取 68 hp := OpenProcess(PROCESS_ALL_ACCESS, False, pid); //打开进程,获得进程句柄 69 ShowMessage('hp' + IntToStr(hp)); //显示进程句柄,如果hp=0则打开失败,需要提权 70 apiaddr := Integer(GetProcAddress(LoadLibrary('msvbvm60.dll'), 'ThunRTMain')); //GetprocAddress获得的地址是point,故用Integer转换成数值 71 // ShowMessage('apiaddr'+IntToStr(apiaddr)); 72 allocaddr := Integer(VirtualAllocEx(hp, nil, 1024, 4096, 4)); //申请一段内存空间,大小为1024,4096是新保护,表示该内存空间可读可写可执行,最后一个参数为旧保护,但是好像必须要写4,否则无法申请 73 写 := Lens(allocaddr, apiaddr); //此时开始计算新申请的内存空间的地址到api地址的距离 74 jmps := 233; //jmp的字节码E9的10进制就是233 75 // ShowMessage(IntToStr(写)); 76 WriteProcessMemory(hp, Pointer(apiaddr), Pointer(@jmps), 1, 实际写); //先写jmp 77 WriteProcessMemory(hp, Pointer(apiaddr + 1), Pointer(@写), 4, 实际写); // 再写距离,第二个参数为地址,第三个参数为要写入的内容,都是Point类型,但要写入的内容,必须要加@,表示保存内容的变量的地址,4表示写入的字节数,也就是大小 78 for i := 1 to 16 do //构造一个循环,从数组里面拿出数据写入申请的内存空间 79 begin 80 if i = 1 then 81 begin 82 asmcode := StrToInt('$' + code[i]); 83 WriteProcessMemory(hp, Pointer(allocaddr), Pointer(@asmcode), 1, 实际写); 84 end 85 else 86 begin 87 asmcode := StrToInt('$' + code[i]); 88 WriteProcessMemory(hp, Pointer(allocaddr + i - 1), 89 Pointer(@asmcode), 1, 实际写); 90 end; 91 WriteProcessMemory(hp, Pointer(allocaddr + 16), Pointer(@jmps), 1, 实际写); //这里是从申请的内存空间跳转回来到api,因为总共是16个字节,所以从第17个字节就是E9,也就是jmp,内存空间是从0开始,非从1开始 92 写 := Lens(apiaddr + 5, allocaddr + 16); 93 WriteProcessMemory(hp, Pointer(allocaddr + 17), Pointer(@写), 4, 实际写); //写入距离 94 VirtualProtectEx(hp, Pointer($401973), 1, 64, oldpro); //最后修改mov byte ptr ds:[0x401973], 0x74 Patch代码,将401973的内存空间 修改成可读可写,也就是64 95 end; 96 97 end; 98 99 exports //Dll的导出函数,使外部程序可以调用的函数 100 apihook; 101 102 begin104 apihook; 105 //这个begin和end之间,个人理解属于启动函数,DllMain 106 end.
附asm代码:
660035A4 > 55 push ebp 函数头直接jmp
660035A5 8BEC mov ebp, esp
660035A7 6A FF push -0x1
660035A9 68 20980166 push 66019820 函数头下面的被jmp回来的地址
660198FE 0000 add byte ptr ds:[eax], al 空代码地址
00401973 /75 43 jnz short 004019B8
660198FE 60 pushad 保存寄存器
660198FF 9C pushfd 保存标志位
66019900 C605 73194000 7>mov byte ptr ds:[0x401973], 0x74 Patch代码
66019907 9D popfd 恢复标志位
66019908 61 popad 恢复寄存器
66019909 55 push ebp 把被Jmp的函数头还原回来
6601990A 8BEC mov ebp, esp
6601990C 6A FF push -0x1
6601990E ^ E9 969CFEFF jmp 660035A9 jmp回去
66019913 90 nop
60 9C C6 05 73 19 40 00 74 9D 61 55 8B EC 6A FF E9 96 9C FE FF 90