无聊拿出来分享一下,送给和我一样菜的朋友,如果有什么不正确的欢迎大家指出
共同学习共同进步嘛,最近在研究WINDOWS的回调机制。又找不到什么好题材,干脆就分析一下
QQ2011 的底层键盘钩子啦,只为学习,希望大家不要拿来做什么违法的事。
首先说下WINDOWS的回调吧,其实回调有点像APC。通俗点讲就是底层调用用户空间函数又
返回底层主要涉及到的函数就是KeUserModeCallback它的作用就是帮回调函数设计好用户空间堆栈
回调函数返回用户空间的时候让它指向用户空间的分派函数KiUserCallbackDispatcher再从
KernelCallbackTable表中以ID找到对应的中继函数,再从底层传回来的结构中的PROC函数指针中
调用我们的(用户空间)回调函数 , 在调用KeUserModeCallback的时候会把三个参数写到用户空间
堆载,KernelCallbackTable的ID,回调函数结构,里面包含了很多信息比如PROC HOOKID
包括底层键盘钩子用到的 KBDLLHOOKSTRUCT结构(lParam),还有个就是这个结构的长度
在调用完用户空间的函数以后再通过NtCallbackReturn返回底层。
顺便说下KernelCallbackTable在PEB+0X2C的位置 XPSP3
下图就是KiUserCallbackDispatcher调用啦 也就是底层回调到用户层的第一步
POP EDX
MOV EAX,DWORD PTR FS:[18]
MOV EAX,DWORD PTR DS:[EAX+30]
MOV EAX,DWORD PTR DS:[EAX+2C] //得到KernelCallbackTable EDX保存着ID
CALL DWORD PTR DS:[EAX+EDX*4]
我们来加载QQ 设置个条件断点看看寄存器和堆栈有什么内容点击密码输入框
按个1,看下
从图可以看到寄存器EDX=2D(ID)
堆栈上
0013FABC 0000002D //ID
0013FAC0 0013FAC8 //回调结构指针
0013FAC4 00000024 //大小
0013FAC8 000D0000 //HOOKID
0013FACC 00000100 //CODE
0013FAD0 020DC191 //回调函数地址 用户空间
0013FAD8 00000031 //这个就是我们输入的1
我们进一步跟进去看看
下图是KernelCallbackTable表以ID调用的函数
//CALL DWORD PTR DS:[EAX+EDX*4] 来到这里
77D58D54 8BFF MOV EDI,EDI
77D58D56 55 PUSH EBP
77D58D57 8BEC MOV EBP,ESP
77D58D59 83EC 0C SUB ESP,0C
77D58D5C 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
77D58D5F FF70 08 PUSH DWORD PTR DS:[EAX+8]//回调函数地址
77D58D62 8D48 10 LEA ECX,DWORD PTR DS:[EAX+10]//结构地址
77D58D65 51 PUSH ECX
77D58D66 FF70 04 PUSH DWORD PTR DS:[EAX+4] //CODE
77D58D69 C745 F8 1400000>MOV DWORD PTR SS:[EBP-8],14
77D58D70 FF30 PUSH DWORD PTR DS:[EAX] //HOOKID
77D58D72 894D FC MOV DWORD PTR SS:[EBP-4],ECX
77D58D75 FF50 0C CALL DWORD PTR DS:[EAX+C]//CALL 77D318D1
到这里就用到我们从底层传上来的结构里的内容啦 我们继续进CALL
//CALL DWORD PTR DS:[EAX+C]//CALL 77D318D1来到这里省略一些钩子类型检测的代码
77D31912 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] //lParam
77D31915 53 PUSH EBX //wParam
77D31916 FF75 0C PUSH DWORD PTR SS:[EBP+C]
77D31919 0FB7FE MOVZX EDI,SI
77D3191C 57 PUSH EDI //nCode
77D3191D 897D F8 MOV DWORD PTR SS:[EBP-8],EDI
77D31920 FF55 14 CALL DWORD PTR SS:[EBP+14]
这里一系列检测完钩子类型以后来到这个CALL这里就是
LRESULT CALLBACK LowLevelKeyboardProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam
这个时候就到了QQ的钩子回调函数啦
020DC191 55 PUSH EBP
020DC192 8BEC MOV EBP,ESP
020DC194 83EC 30 SUB ESP,30
020DC197 56 PUSH ESI
020DC198 57 PUSH EDI
020DC199 C745 FC 78BF0D0>MOV DWORD PTR SS:[EBP-4],20DBF78
/*注意这里这里有个基址很重要很多函数的定位和数据的定位都是它*/
020DC1A0 8D7D D0 LEA EDI,DWORD PTR SS:[EBP-30]
020DC1A3 B9 07000000 MOV ECX,7
020DC1A8 33C0 XOR EAX,EAX
020DC1AA FC CLD
020DC1AB F3:AB REP STOS DWORD PTR ES:[EDI]
020DC1AD 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10]//获取KBDLLHOOKSTRUCT
020DC1B0 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX//保存
020DC1B3 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]//基地址定位判断
020DC1B6 8379 0C 00 CMP DWORD PTR DS:[ECX+C],0
020DC1BA 74 21 JE SHORT 020DC1DD
020DC1BC 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
020DC1BF FF52 54 CALL DWORD PTR DS:[EDX+54]// GetForegroundWindow调用判断
窗口
HWND hwnd=GetForegroundWindow();
_asm{
mov edx,0x20DBF78
mov edx,[edx+0x1c]
cmp hwnd,edx
jnz 020DC1DD
}
020DC1C2 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]//取基地址
020DC1C5 3B42 1C CMP EAX,DWORD PTR DS:[EDX+1C]//+1C位置存放着窗口句柄比较
020DC1C8 75 13 JNZ SHORT 020DC1DD
020DC1CA 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC1CD 8B41 08 MOV EAX,DWORD PTR DS:[ECX+8]
020DC1D0 8945 CC MOV DWORD PTR SS:[EBP-34],EAX
020DC1D3 B8 10000000 MOV EAX,10
020DC1D8 F7D0 NOT EAX
020DC1DA 2141 08 AND DWORD PTR DS:[ECX+8],EAX
020DC1DD C745 F4 0000000>MOV DWORD PTR SS:[EBP-C],0
020DC1E4 E8 20000000 CALL 020DC209 //上面的跳转如果不成立就到这个CALL
{020DC209 5F POP EDI //此时EDI等下返回地址 也就是-》 020DC1E9
020DC20A 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]
020DC20D 833C8F 00 CMP DWORD PTR DS:[EDI+ECX*4],0
020DC211 74 1D JE SHORT 020DC230
020DC213 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
020DC216 8B0497 MOV EAX,DWORD PTR DS:[EDI+EDX*4]//取020DC1E9的代码
020DC219 50 PUSH EAX
020DC21A 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
020DC21D FF51 50 CALL DWORD PTR DS:[ECX+50]
/* 调用GetAsyncKeyState判断被按下 餐宿EAX=020DC1E9的代码
实际上20DC1E9 是020DC1E9 00000010
020DC1ED 00000011
020DC1F1 00000012
020DC1F5 00000013
020DC1F9 00000009
020DC1FD 0000005B
020DC201 0000005C
循环判断知道遇到0结束
*/
020DC220 0FBFD0 MOVSX EDX,AX
020DC223 81E2 00800000 AND EDX,8000
020DC229 75 05 JNZ SHORT 020DC230
020DC22B FF45 F4 INC DWORD PTR SS:[EBP-C]
020DC22E ^ EB DA JMP SHORT 020DC20A
020DC230 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]//KBDLLHOOKSTRUCT
020DC233 8B02 MOV EAX,DWORD PTR DS:[EDX] //KBDLLHOOKSTRUCT->vkCode也就是我们按下的1=31
020DC235 C745 F0 0000000>MOV DWORD PTR SS:[EBP-10],0
020DC23C E8 3C000000 CALL 020DC27D
这里来到下个CALL进入这个CALL再下面大家往下看
}
020DC1E9 1000 ADC BYTE PTR DS:[EAX],AL
020DC1EB 0000 ADD BYTE PTR DS:[EAX],AL
020DC1ED 1100 ADC DWORD PTR DS:[EAX],EAX
020DC1EF 0000 ADD BYTE PTR DS:[EAX],AL
020DC1F1 1200 ADC AL,BYTE PTR DS:[EAX]
020DC1F3 0000 ADD BYTE PTR DS:[EAX],AL
020DC1F5 1300 ADC EAX,DWORD PTR DS:[EAX]
020DC1F7 0000 ADD BYTE PTR DS:[EAX],AL
020DC1F9 0900 OR DWORD PTR DS:[EAX],EAX
020DC1FB 0000 ADD BYTE PTR DS:[EAX],AL
020DC1FD 5B POP EBX
020DC1FE 0000 ADD BYTE PTR DS:[EAX],AL
020DC200 005C00 00 ADD BYTE PTR DS:[EAX+EAX],BL
020DC204 0000 ADD BYTE PTR DS:[EAX],AL
020DC206 0000 ADD BYTE PTR DS:[EAX],AL
020DC208 005F 8B ADD BYTE PTR DS:[EDI-75],BL
020DC20B 4D DEC EBP
020DC20C F4 HLT
020DC20D 833C8F 00 CMP DWORD PTR DS:[EDI+ECX*4],0
020DC211 74 1D JE SHORT 020DC230
020DC213 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
020DC216 8B0497 MOV EAX,DWORD PTR DS:[EDI+EDX*4]
020DC219 50 PUSH EAX
020DC21A 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
020DC21D FF51 50 CALL DWORD PTR DS:[ECX+50]
020DC220 0FBFD0 MOVSX EDX,AX
020DC223 81E2 00800000 AND EDX,8000
020DC229 75 05 JNZ SHORT 020DC230
020DC22B FF45 F4 INC DWORD PTR SS:[EBP-C]
020DC22E ^ EB DA JMP SHORT 020DC20A
020DC230 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]
020DC233 8B02 MOV EAX,DWORD PTR DS:[EDX]
020DC235 C745 F0 0000000>MOV DWORD PTR SS:[EBP-10],0
020DC23C E8 3C000000 CALL 020DC27D
020DC241 1000 ADC BYTE PTR DS:[EAX],AL
020DC243 0000 ADD BYTE PTR DS:[EAX],AL
020DC245 1100 ADC DWORD PTR DS:[EAX],EAX
020DC247 0000 ADD BYTE PTR DS:[EAX],AL
020DC249 1200 ADC AL,BYTE PTR DS:[EAX]
020DC24B 0000 ADD BYTE PTR DS:[EAX],AL
020DC24D 1300 ADC EAX,DWORD PTR DS:[EAX]
020DC24F 0000 ADD BYTE PTR DS:[EAX],AL
020DC251 5B POP EBX
020DC252 0000 ADD BYTE PTR DS:[EAX],AL
020DC254 005C00 00 ADD BYTE PTR DS:[EAX+EAX],BL
020DC258 005D 00 ADD BYTE PTR SS:[EBP],BL
020DC25B 0000 ADD BYTE PTR DS:[EAX],AL
020DC25D 90 NOP
020DC25E 0000 ADD BYTE PTR DS:[EAX],AL
020DC260 00A0 000000A1 ADD BYTE PTR DS:[EAX+A1000000],AH
020DC266 0000 ADD BYTE PTR DS:[EAX],AL
020DC268 00A2 000000A3 ADD BYTE PTR DS:[EDX+A3000000],AH
020DC26E 0000 ADD BYTE PTR DS:[EAX],AL
020DC270 00A400 0000A500 ADD BYTE PTR DS:[EAX+EAX+A50000],AH
020DC277 0000 ADD BYTE PTR DS:[EAX],AL
020DC279 0000 ADD BYTE PTR DS:[EAX],AL
020DC27B 0000 ADD BYTE PTR DS:[EAX],AL
020DC27D 5E POP ESI
020DC27E 8B4D F0 MOV ECX,DWORD PTR SS:[EBP-10]
020DC281 833C8E 00 CMP DWORD PTR DS:[ESI+ECX*4],0
020DC285 74 0A JE SHORT 020DC291
020DC287 3B048E CMP EAX,DWORD PTR DS:[ESI+ECX*4]
020DC28A 74 05 JE SHORT 020DC291
020DC28C FF45 F0 INC DWORD PTR SS:[EBP-10]
020DC28F ^ EB ED JMP SHORT 020DC27E
/*
我们按下的虚拟键和下面的值比较
020DC241 00000010
020DC245 00000011
020DC249 00000012
020DC24D 00000013
020DC251 0000005B
020DC255 0000005C
020DC259 0000005D
020DC25D 00000090
020DC261 000000A0
020DC265 000000A1
020DC269 000000A2
020DC26D 000000A3
020DC271 000000A4
020DC275 000000A5
020DC279 00000000
*/
020DC291 837D 08 00 CMP DWORD PTR SS:[EBP+8],0
020DC295 7C 4E JL SHORT 020DC2E5
020DC297 817D 0C 0001000>CMP DWORD PTR SS:[EBP+C],100
020DC29E 74 09 JE SHORT 020DC2A9
020DC2A0 817D 0C 0101000>CMP DWORD PTR SS:[EBP+C],101
020DC2A7 75 3C JNZ SHORT 020DC2E5
020DC2A9 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC2AC 8139 FF000000 CMP DWORD PTR DS:[ECX],0FF
020DC2B2 75 31 JNZ SHORT 020DC2E5
/*
比较钩子类型状态和虚拟键最终跳到020DC2E5
*/
020DC2B4 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC2B7 8B51 0C MOV EDX,DWORD PTR DS:[ECX+C]
020DC2BA 81F2 56B7C7E8 XOR EDX,E8C7B756
020DC2C0 3951 10 CMP DWORD PTR DS:[ECX+10],EDX
020DC2C3 75 20 JNZ SHORT 020DC2E5
020DC2C5 6A 00 PUSH 0
020DC2C7 6A 00 PUSH 0
020DC2C9 68 04140000 PUSH 1404
020DC2CE 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
020DC2D1 8B42 18 MOV EAX,DWORD PTR DS:[EDX+18]
020DC2D4 50 PUSH EAX
020DC2D5 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
020DC2D8 FF51 44 CALL DWORD PTR DS:[ECX+44]
020DC2DB B8 01000000 MOV EAX,1
020DC2E0 E9 54020000 JMP 020DC539
020DC2E5 837D 08 00 CMP DWORD PTR SS:[EBP+8],0
020DC2E9 0F8C E1010000 JL 020DC4D0
020DC2EF 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
020DC2F2 8379 0C 00 CMP DWORD PTR DS:[ECX+C],0
020DC2F6 0F84 D4010000 JE 020DC4D0
020DC2FC 817D 0C 0001000>CMP DWORD PTR SS:[EBP+C],100
020DC303 74 0D JE SHORT 020DC312
020DC305 817D 0C 0101000>CMP DWORD PTR SS:[EBP+C],101
020DC30C 0F85 BE010000 JNZ 020DC4D0
020DC312 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC315 8379 10 20 CMP DWORD PTR DS:[ECX+10],20
020DC319 0F84 B1010000 JE 020DC4D0
020DC31F 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC322 8379 10 21 CMP DWORD PTR DS:[ECX+10],21
020DC326 0F84 A4010000 JE 020DC4D0
020DC32C 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC32F 8379 10 22 CMP DWORD PTR DS:[ECX+10],22
020DC333 0F84 97010000 JE 020DC4D0
020DC339 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
020DC33C 8B51 24 MOV EDX,DWORD PTR DS:[ECX+24]
020DC33F 33C0 XOR EAX,EAX
020DC341 8A02 MOV AL,BYTE PTR DS:[EDX]
020DC343 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC346 3901 CMP DWORD PTR DS:[ECX],EAX
020DC348 0F82 82010000 JB 020DC4D0
/*经过一系列参数的比较来到这里注意下面*/
020DC34E 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4] //取出刚才的基址20DBF78
020DC351 8B42 24 MOV EAX,DWORD PTR DS:[EDX+24]//[20DBF78+0X24]
020DC354 33C9 XOR ECX,ECX
020DC356 8A48 01 MOV CL,BYTE PTR DS:[EAX+1]
020DC359 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]
020DC35C 390A CMP DWORD PTR DS:[EDX],ECX
020DC35E 0F87 6C010000 JA 020DC4D0
020DC364 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC367 8B09 MOV ECX,DWORD PTR DS:[ECX]
020DC369 81E1 FF000000 AND ECX,0FF
020DC36F 81F9 A0000000 CMP ECX,0A0
020DC375 0F84 55010000 JE 020DC4D0
020DC37B 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC37E 8B09 MOV ECX,DWORD PTR DS:[ECX]
020DC380 81E1 FF000000 AND ECX,0FF
020DC386 81F9 A1000000 CMP ECX,0A1
020DC38C 0F84 3E010000 JE 020DC4D0
020DC392 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC395 8B09 MOV ECX,DWORD PTR DS:[ECX]
020DC397 81E1 FF000000 AND ECX,0FF
020DC39D 81F9 A2000000 CMP ECX,0A2
020DC3A3 0F84 27010000 JE 020DC4D0
020DC3A9 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC3AC 8B09 MOV ECX,DWORD PTR DS:[ECX]
020DC3AE 81E1 FF000000 AND ECX,0FF
020DC3B4 81F9 A3000000 CMP ECX,0A3
020DC3BA 0F84 10010000 JE 020DC4D0
020DC3C0 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC3C3 8B09 MOV ECX,DWORD PTR DS:[ECX]
020DC3C5 81E1 FF000000 AND ECX,0FF
020DC3CB 81F9 A4000000 CMP ECX,0A4
020DC3D1 0F84 F9000000 JE 020DC4D0
020DC3D7 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC3DA 8B09 MOV ECX,DWORD PTR DS:[ECX]
020DC3DC 81E1 FF000000 AND ECX,0FF
020DC3E2 81F9 A5000000 CMP ECX,0A5
020DC3E8 0F84 E2000000 JE 020DC4D0
/*
打字好麻烦我上面一段用伪代码来表示
a=0x31;//我们按下的虚拟键1
if(a==0||(a&0xff)==0xa1||(a&0xff)==0xa2||(a&0xff)==0xa3||(a&0xff)==0xa4||(a&0xff)==0xa5)
{
JMP 20DC4D0 这里调用 CallNextHookEx 钩子链下个钩子
}
*/
020DC3EE 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
020DC3F1 FF52 54 CALL DWORD PTR DS:[EDX+54]
020DC3F4 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
020DC3F7 3B42 1C CMP EAX,DWORD PTR DS:[EDX+1C]
020DC3FA 0F85 D0000000 JNZ 020DC4D0
/*继续比较窗口不是就跳
EDX=20dbf78刚才的基址
EDX+1C=QQ登陆框的句柄
EDX+18=QQ密码框的句柄
*/
020DC400 8365 CC 10 AND DWORD PTR SS:[EBP-34],10
020DC404 837D CC 00 CMP DWORD PTR SS:[EBP-34],0
020DC408 74 2C JE SHORT 020DC436
/*这里跳到020DC436*/
020DC40A 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC40D 8B11 MOV EDX,DWORD PTR DS:[ECX]
020DC40F 52 PUSH EDX
020DC410 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
020DC413 8B48 0C MOV ECX,DWORD PTR DS:[EAX+C]
020DC416 51 PUSH ECX
020DC417 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
020DC41A 8B42 20 MOV EAX,DWORD PTR DS:[EDX+20]
020DC41D 8B08 MOV ECX,DWORD PTR DS:[EAX]
020DC41F 51 PUSH ECX
020DC420 8B55 0C MOV EDX,DWORD PTR SS:[EBP+C]
020DC423 52 PUSH EDX
020DC424 E8 13FDFFFF CALL 020DC13C
020DC429 85C0 TEST EAX,EAX
020DC42B 75 09 JNZ SHORT 020DC436
020DC42D C745 E0 2200000>MOV DWORD PTR SS:[EBP-20],22
020DC434 EB 07 JMP SHORT 020DC43D
020DC436 C745 E0 2100000>MOV DWORD PTR SS:[EBP-20],21
020DC43D C745 D0 0100000>MOV DWORD PTR SS:[EBP-30],1
020DC444 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
020DC447 833C87 00 CMP DWORD PTR DS:[EDI+EAX*4],0
020DC44B 75 2E JNZ SHORT 020DC47B
020DC44D 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
020DC450 833C86 00 CMP DWORD PTR DS:[ESI+EAX*4],0
020DC454 75 25 JNZ SHORT 020DC47B
020DC456 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]//取基地址
020DC459 8B51 24 MOV EDX,DWORD PTR DS:[ECX+24]//取基地址+24
020DC45C 8BCA MOV ECX,EDX //送到ECX
020DC45E 33C0 XOR EAX,EAX
020DC460 8A01 MOV AL,BYTE PTR DS:[ECX]
020DC462 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]//取KBDLLHOOKSTRUCT
020DC465 8B09 MOV ECX,DWORD PTR DS:[ECX]//取我们的虚拟键
020DC467 2BC8 SUB ECX,EAX
020DC469 81E1 FF000000 AND ECX,0FF
020DC46F 66:0FB65411 02 MOVZX DX,BYTE PTR DS:[ECX+EDX+2]
/*
这段是最终的结果啦 以我们的虚拟键为下标从 基地址+24下的地址再+2取出值(就是AS的38也就是8)
这下面是什么值呢我们看下图 看见吗就是我们所说的乱码啦
*/
020DC475 66:8955 D4 MOV WORD PTR SS:[EBP-2C],DX
/*
这个时候DX变成了38=[ECX+EDX+2]
ECX=我们按下的虚拟键 EDX=[20DBF78+24]*/
020DC479 EB 16 JMP SHORT 020DC491 //跳到20DC491
020DC47B C745 E0 2000000>MOV DWORD PTR SS:[EBP-20],20
020DC482 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
020DC485 8B09 MOV ECX,DWORD PTR DS:[ECX]
020DC487 81E1 FF000000 AND ECX,0FF
020DC48D 66:894D D4 MOV WORD PTR SS:[EBP-2C],CX
/*跳到这里*/
020DC491 6A 00 PUSH 0
020DC493 0FB745 D4 MOVZX EAX,WORD PTR SS:[EBP-2C]
020DC497 50 PUSH EAX
020DC498 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
020DC49B FF52 48 CALL DWORD PTR DS:[EDX+48]
/*这里调用MapVirtualKeyA函数转换虚拟键
*/
020DC49E 66:8945 D6 MOV WORD PTR SS:[EBP-2A],AX//保存其实这里[EBP-2A]是个结构我们往下看
020DC4A2 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
020DC4A5 8B48 0C MOV ECX,DWORD PTR DS:[EAX+C]
020DC4A8 894D DC MOV DWORD PTR SS:[EBP-24],ECX
020DC4AB 817D 0C 0101000>CMP DWORD PTR SS:[EBP+C],101
020DC4B2 75 07 JNZ SHORT 020DC4BB //这里跳啦
020DC4B4 C745 D8 0200000>MOV DWORD PTR SS:[EBP-28],2
/*这里就是最终结果啦*/
020DC4BB 6A 1C PUSH 1C //结构大小cbSize
020DC4BD 8D55 D0 LEA EDX,DWORD PTR SS:[EBP-30]
020DC4C0 52 PUSH EDX//就是[EBP-2A]是个结构
020DC4C1 6A 01 PUSH 1//nInputs
020DC4C3 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
020DC4C6 FF50 4C CALL DWORD PTR DS:[EAX+4C]//SendInput
/*
调用SendInput
typedef struct tagINPUT {
DWORD type;
union
{
MOUSEINPUT mi;
KEYBDINPUT ki;//TYPE为键盘时的结构typedef struct tagKEYBDINPUT {
WORD wVk;
WORD wScan;
DWORD dwFlags;
DWORD time;
DWORD dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT, FAR* LPKEYBDINPUT;
HARDWAREINPUT hi;
};
} INPUT, *PINPUT, FAR* LPINPUT;<------[EBP-30]
我们开始输入的31 这个时候变成了38所以说很多情况下抓不到正确的数据
主要是通过这一系列的转换最终由SendInput结束。
MOVZX DX,BYTE PTR DS:[ECX+EDX+2] 这个是转换的关键,记得那个基地址很重要
*/
020DC4C9 B8 01000000 MOV EAX,1
020DC4CE EB 69 JMP SHORT 020DC539//这里就跳到结束啦
020DC4D0 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]
020DC4D3 8B02 MOV EAX,DWORD PTR DS:[EDX]
020DC4D5 C745 EC 0000000>MOV DWORD PTR SS:[EBP-14],0
020DC4DC E8 0C000000 CALL 020DC4ED
020DC4E1 5D POP EBP
020DC4E2 0000 ADD BYTE PTR DS:[EAX],AL
020DC4E4 0079 00 ADD BYTE PTR DS:[ECX],BH
020DC4E7 0000 ADD BYTE PTR DS:[EAX],AL
020DC4E9 0000 ADD BYTE PTR DS:[EAX],AL
020DC4EB 0000 ADD BYTE PTR DS:[EAX],AL
020DC4ED 5E POP ESI
020DC4EE 8B4D EC MOV ECX,DWORD PTR SS:[EBP-14]
020DC4F1 833C8E 00 CMP DWORD PTR DS:[ESI+ECX*4],0
020DC4F5 74 0A JE SHORT 020DC501
020DC4F7 3B048E CMP EAX,DWORD PTR DS:[ESI+ECX*4]
020DC4FA 74 05 JE SHORT 020DC501
020DC4FC FF45 EC INC DWORD PTR SS:[EBP-14]
020DC4FF ^ EB ED JMP SHORT 020DC4EE
020DC501 837D 08 00 CMP DWORD PTR SS:[EBP+8],0
020DC505 7C 19 JL SHORT 020DC520
020DC507 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
020DC50A 8379 0C 00 CMP DWORD PTR DS:[ECX+C],0
020DC50E 74 10 JE SHORT 020DC520
020DC510 8B55 EC MOV EDX,DWORD PTR SS:[EBP-14]
020DC513 833C96 00 CMP DWORD PTR DS:[ESI+EDX*4],0
020DC517 74 07 JE SHORT 020DC520
020DC519 B8 01000000 MOV EAX,1
020DC51E EB 19 JMP SHORT 020DC539
020DC520 8B4D 10 MOV ECX,DWORD PTR SS:[EBP+10]
020DC523 51 PUSH ECX
020DC524 8B55 0C MOV EDX,DWORD PTR SS:[EBP+C]
020DC527 52 PUSH EDX
020DC528 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
020DC52B 50 PUSH EAX
020DC52C 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
020DC52F 8B51 14 MOV EDX,DWORD PTR DS:[ECX+14]
020DC532 52 PUSH EDX
020DC533 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
020DC536 FF50 38 CALL DWORD PTR DS:[EAX+38]
020DC539 5F POP EDI
020DC53A 5E POP ESI
020DC53B 8BE5 MOV ESP,EBP
020DC53D 5D POP EBP
020DC53E C2 0C00 RETN 0C
由于时间比较匆忙只能写这么多啦,大家注意文中我说的那个基址很多函数的定位
和一些数据都靠它来定位。 还有一些内存校验呀,反调试功能等东西
下次有时间再写啦,如果有什么不对的地方,请大家指正,共同学习共同进步嘛!
我相信很多人能写出截取密码的代码,连我这么笨的人都能有几种方法截取,何况论坛上的大牛
们,所以代码我就不放上来啦,第一 怕一些人拿代码做些违法的事,我是以学习技术为主。
第二 我代码写得比较烂,不好意思拿出来丢人。所以大家谅解一下拉。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!