看雪论坛看了《逆向RING0程序从这里开始》一文,汇编看得不是太流畅,对一些指令还要查资料。
今特写下来已加强印象。
rep:重复前缀,ecx为计数器进行重复,
repz,repe:0标志被设置且ecx〉0重复
repnz,repne: 0标志被清除且ecx〉0重复
movsb,movsw ,movsd:从ESI指向的内存位置拷贝数据到EDI指向的内存位置。同时ESI和EDI寄存器自动增加或减少(依据方向标志的值而定),
方向标志可由
CLD(清除方向标志, 寻址低--〉高)、STD(设置方向标志 高--〉低)显式改变
例如:(以下片断摘自提到的该文,感谢)
push 7
.text:000105A2 pop ecx
.text:000105A3 mov esi, offset s_DeviceHdhook ; "//Device//HDHOOK"
.text:000105A8 lea edi, [ebp+regnameNt]
.text:000105AE push 9
.text:000105B0 rep movsd
.text:000105B2 movsw
stosb/stosw/stosd:将al/ax/eax的内容存储在edi指向的内存单元中,同时edi的值将依据方向标志的值增加或减少。
lodsb/lodsw/lodsd:将从esi指向的内存位置向al/ax/eax中装入一个值。同时esi的值将依据方向标志的值增加或减少。
movzx ,将源操作数(第二操作数)的内容拷贝到目的操作数(第一操作数)中,并将该值0扩展到16位或32位。只能用于无符号整数。目的操作数必须为寄存器。
movsx,将源操作数(第二操作数)的内容拷贝到目的操作数(第一操作数)中,并将该值符号扩展到16位或32位。只能用于有符号整数
例:
.text:000105FA mov ax, [esi]
.text:000105FD add ax, 2
.text:00010601 movzx ecx, ax
.text:00010604 mov edx, ecx
.text:00010606 xor eax, eax
.text:00010608 shr ecx, 2
.text:0001060B rep stosd
.text:0001060D mov ecx, edx
.text:0001060F and ecx, 3
.text:00010612 rep stosb
相当于RtlZeroMemory,先是4字节对齐的填0,然后使用AND取得除以4后的余数,继续填0。
系统的RtlZeroMemory的代码
00402520: 57 PUSH EDI
00402521: 8B7C2408 MOV EDI, [ESP+08]
00402525: 8B4C240C MOV ECX, [ESP+0C]
00402529: 33C0 XOR EAX, EAX
0040252B: FC CLD ;这一句用来保证DF=0
0040252C: 8BD1 MOV EDX, ECX
0040252E: 83E203 AND EDX, 00000003;除以4的余数
00402531: C1E902 SHR ECX, 02;除以4的商
00402534: F3AB REP STOSD
00402536: 0BCA OR ECX, EDX
00402538: 7504 JNZ 40253E;非4字节对齐,继续填0
0040253A: 5F POP EDI
0040253B: C20800 RETN 0008
0040253E: F3AA REP STOSB
00402540: 5F POP EDI
00402541: C20800 RETN 0008
scas /scasb /scasw 串扫描指令SCAS将edi指向的字节或字内容与AL/AX寄存器内容进行比较,根据比较的结果设置标志,每次比较后修改EDI寄存器的值,使之指向下一个元素。
以下代码片断,源于upx加密壳,恢复被加壳exe的IAT功能。edi指向以01分割的调用函数名称串。
如下示:
0040EA79 53 00 00 01 5F 6C 77 72 69 74 65 00 01 44 65 6C S.._lwrite.Del
0040D015 65 74 65 46 69 6C 65 41 00 01 5F 6C 63 6C 6F 73 eteFileA._lclos
0040D025 65 00 01 5F 6C 6F 70 65 6E 00 01 4C 6F 63 61 6C e._lopen.Local
0040D035 55 6E 6C 6F 63 6B 00 01 5F 6C 63 72 65 61 74 00 Unlock._lcreat.
0040D045 01 5F 6C 6C 73 65 65 6B 00 01 4C 6F 63 61 6C 52 _llseek.LocalR
0040D055 65 41 6C 6C 6F 63 00 eAlloc.
0040EA79 > /8A07 mov al, byte ptr [edi];al=01
0040EA7B . |47 inc edi
0040EA7C . |08C0 or al, al
0040EA7E .^|74 DC je short 0040EA5C ;跳到下一个模块
0040EA80 . |89F9 mov ecx, edi
0040EA82 . |57 push edi;API函数名称
0040EA83 . |48 dec eax;执行后 al=0
0040EA84 . |F2:AE repne scas byte ptr es:[edi];扫描,直到遇到0
0040EA86 . |55 push ebp
0040EA87 . |FF96 A4EC0000 call dword ptr [esi+ECA4] ; kernel32.GetProcAddress
0040EA8D . |09C0 or eax, eax
0040EA8F . |74 07 je short 0040EA98
0040EA91 . |8903 mov dword ptr [ebx], eax;填充IAT
0040EA93 . |83C3 04 add ebx, 4
0040EA96 .^/EB E1 jmp short 0040EA79
jmp指令
jmp是相对跳转,跳转到相对当前地址的偏移处。相对当前地址是指当前指令地址加上指令长度。例如:
0040123F E9 CC 05 00 00 E9 67 樘...間
00401246 1F 00 00
000005cc + (0040123f + 5) = 00401810