这是偶无聊的时候跟踪金山游侠的部分代码,并用汇编根据其程序流程写出了完整的代码,就当练练手吧!
0041EC32 /. 55 push ebp ;后面要用EBP读堆栈找外部参数所以就要先保存EBP
0041EC33 |. 8BEC mov ebp, esp ;用EBP读堆栈,以为ESP在不断变化
0041EC35 |. 51 push ecx
0041EC36 |. 56 push esi
0041EC37 |. 57 push edi ;以上为保存3个寄存器的值
0041EC38 |. FF71 20 push dword ptr [ecx+20] ; /打开的进程ID,第三个参数
0041EC3B |. 6A 00 push 0 ; |句柄是否可以被继承,0为不继承,第二个参数
0041EC3D |. 6A 10 push 10 ; |打开进程权限,这里是读权限,第一个参数
0041EC3F |. FF15 78F34500 call dword ptr [<&KERNEL32.OpenProcess>] ; /打开进程函数,要使用就得先打开
0041EC45 |. 8BF0 mov esi, eax ; 把EAX中的返回句柄保存到ESI中
0041EC47 |. 85F6 test esi, esi ; 测试ESI,就是看函数是否执行成功
0041EC49 |. 74 35 je short 0041EC80 ; 不成功的话跳到子程序末尾
0041EC4B |. 8B7D 10 mov edi, dword ptr [ebp+10] ; 把外部第3个参数保存到EDI
0041EC4E |. 8D45 FC lea eax, dword ptr [ebp-4] ; PUSH ECX时在内存中的值
0041EC51 |. 50 push eax ; /返回实际读取数,第五个参数
0041EC52 |. 57 push edi ; |要读写的字节数[EBP+10]中的值,第四个参数
0041EC53 |. FF75 0C push dword ptr [ebp+C] ; |接收读取数值的缓冲区,第三个参数
0041EC56 |. 8365 FC 00 and dword ptr [ebp-4], 0 ; |把返回实际读取数缓冲区初始为0
0041EC5A |. FF75 08 push dword ptr [ebp+8] ; |起始地址,第二个参数
0041EC5D |. 56 push esi ; |句柄,第一个参数
0041EC5E |. FF15 74F34500 call dword ptr [<&KERNEL32.ReadProcessMemory>] ; /读进程内存
0041EC64 |. 85C0 test eax, eax ; 测试函数返回值
0041EC66 |. 74 11 je short 0041EC79 ; 不成功的话跳到子程序末尾
0041EC68 |. 397D FC cmp dword ptr [ebp-4], edi ; 比较设定读取长度和返回长度是否一样
0041EC6B |. 75 0C jnz short 0041EC79 ; 不一样的话跳到子程序末尾
0041EC6D |. 56 push esi ; /进程ID,第一个参数
0041EC6E |. FF15 A0F34500 call dword ptr [<&KERNEL32.CloseHandle>] ; /结束进程
0041EC74 |. 6A 01 push 1 ;把1压入堆栈
0041EC76 |. 58 pop eax ;把刚才的1弹到EAX
0041EC77 |. EB 09 jmp short 0041EC82 ;无条件跳
0041EC79 |> 56 push esi ; /进程ID,第一个参数
0041EC7A |. FF15 A0F34500 call dword ptr [<&KERNEL32.CloseHandle>] ; /结束进程
0041EC80 |> 33C0 xor eax, eax ;EAX清O
0041EC82 |> 5F pop edi
0041EC83 |. 5E pop esi ;把先前保存的EDI和ESI还原
0041EC84 |. C9 leave
0041EC85 /. C2 0C00 retn 0C ;返回并清理堆栈中12个字节
以下是用汇编写的代码,为了大家能看懂我没大量使用汇编指令,我使用高级语言的结构描述
_myReadProcessMemory proc uses edi esi lpBaseAddress,lpBuffer,dwSize ;
local @lpNumberOfByteRead ;局部变量,保存返回读取的实际字数
invoke OpenProcess,PROCESS_VM_READ,NULL, ;以读的方式打开进程,最后一个参数是进程句柄我没写,因为我不知道push dword ptr [ecx+20]是怎么得到进程句柄的,谁能告诉我?
mov esi, eax ;把EAX中的返回句柄保存到ESI中
.if esi == 1 ;判断函数是否执行成功
mov edi,dwSize ;把dwSize参数保存到EDI
lea eax,@lpNumberOfByteRead ;把@lpNumberOfByteRead地址装到EAX里
invoke ReadProcessMemory,esi,lpBaseAddress,lpBuffer,dwSize,eax ;读内存
.if eax == 1 ;判断函数是否执行成功
.if @lpNumberOfByteRead == edi ;比较设定读取长度和返回长度是否一样
invoke CloseHandle,esi ;结束进程
push 1 ;把1压入堆栈
pop eax ;把刚才的1弹到EAX做为返回值,因为程序返回时默认把返回值压到EAX中
jmp _end ;条到结尾
.endif
.endif
invoke CloseHandle,esi ;结束进程
.endif
xor eax,eax ;EAX清O,因为程序返回时默认把返回值压到EAX中,返回0说明没执行成功
_end:
ret ;返回
_myReadProcessMemory endp
BY:晓斌
QQ:6750333