编写shellcode时,一般需使用一些API函数,例如CreateProcess(),socket()等,这些函数的入口地址位于系统的动态链接库中,由于不同操作系统的动态链接库的加载地址不同,shellcode中需增加API函数自搜索功能。

shellcode

shellcode是一段用于利用软件漏洞而执行的代码,shellcode为16进制的机器码,因为经常让攻击者获得shell而得名。shellcode常常使用机器语言编写。 可在暂存器eip溢出后,塞入一段可让CPU执行的shellcode机器码,让电脑可以执行攻击者的任意指令。

获取步骤

  1. 定位kernel32.dll地址
    1) 通过段选择字FS在内存中找到当前的线程控制模块TEB
    2) 线程控制块中偏移位置为0x30的地方存放着指向进程控制块PEB的指针
    3) 进程控制块中偏移地址0x0c的地址存放着指向PEB_LDA_DATA结构体的指针,其中存放着已经被装载的动态链接库信息。
    4) PEB_LDA_DATA结构体偏移地址为0x1c的地方存放着指向模块初始化链表的头指针InInitializationOrderModulelist。
    5) 模块初始化链表InInitializationOrderModulelist中按顺序存放着PE装入运行时初始化模块信息,第一个链表节点是ntdll.dll,第二个链表节点就是kernel32.dll。
    6) 找到属于kernel32.dll的节点后,在此基础上再便宜0x08就是kernel32.dll在内存中的价值基地址。
  2. 定位LoadLibrary()及GetProcAddress()地址
    1) 从kernel32.dll的加载基地址开始偏移0x3c的地方就是其PE头
    2) PE头偏移0x78的地方存放着指向函数导出表的指针。
    3) 按以下方式在导出表中算出所需函数的入口地址
    (1)导出表偏移0x1c处的指针指向存储导出函数偏移地址(RVA)的列表
    (2)导出表偏移0x20处的指针指向存储导出函数函数名的列表
    (3)函数的RVA地址和名称按顺序放在RVA列表及函数名列表中,根据函数名在函数名称列表中搜索函数序号,再根据函数序号在RVA列表中搜索函数对应的RVA
    (4)函数对应的RVA加上动态链接库的加载地址得到该函数的虚拟地址。

汇编代码

.386

.model flat,stdcall

option casemap:none

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\masm32.lib

include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\gdi32.inc
include \masm32\include\windows.inc
include \masm32\include\msvcrt.inc
include \masm32\include\masm32.inc
include \masm32\macros\macros.asm
.data
mesg1 db 'kernel32.dll地址: %x ',0ah , 0
mesg2 db 'LoadLibrary()地址: %x ',0ah , 0
mesg3 db 'GetProcAddress()地址: %x',0ah , 0
mesg4 db "GetProcAddress",0
mesg6 db "LoadLibraryA",0
mesg7 db "test:%x",0
add_b dd ?
.code
start:
assume fs:nothing
MOV EBX,FS:[30H]                
MOV EBX,[EBX+0CH]               
MOV EBX,[EBX+14H]               
MOV EBX,[EBX]             
MOV EBX,[EBX]                 
MOV EBP,[EBX+10H]                       
invoke crt_printf,  addr mesg1,EBP ;kernel32.dll地址
MOV EAX,[EBP+3CH]       
MOV ECX,[EBP+EAX+78H]
ADD ECX,EBP          
MOV add_b,ECX           
MOV EBX,[ECX+20H]
ADD EBX,EBP                         ;导出函数名列表指基地址
;invoke crt_printf,  addr mesg7,EBX 

XOR EDI,EDI                         ;清零EDI
first:                            ;GetProcAddress
INC EDI
MOV ESI,[EBX+EDI*4]
ADD ESI,EBP                        ;esi = 函数名称所在地址
invoke lstrcmp, addr mesg4, ESI
.if EAX==0  
MOV EBX,dword ptr[add_b]
MOV EBX,[EBX+24H] 
ADD EBX,EBP                        ;地址表的基地址(rva中的序号表)
MOVZX EBX,WORD PTR[EBX+2*EDI]                 
MOV EAX,EBX
MOV EBX,dword ptr[add_b]           ;实际序号
MOV EBX,[EBX+1CH]
ADD EBX,EBP                     
MOV EBX,[EBX+4*EAX]                 
ADD EBX,EBP                        ;实际地址
invoke crt_printf,  addr mesg3, EBX
.else
JMP first
.endif 
MOV ECX,add_b
MOV EBX,[ECX+20H]
ADD EBX,EBP                         ;导出函数名列表指基地址
;invoke crt_printf,  addr mesg7, EBX

XOR EDI,EDI
second:                          ;LoadLibrary
INC EDI
MOV ESI,[EBX+EDI*4]
ADD ESI,EBP                        ;esi = 函数名称所在地址
invoke lstrcmp, addr mesg6, ESI
.if eax==0  
MOV EBX,dword ptr[add_b]
MOV EBX,[EBX+24H] 
ADD EBX,EBP                        ;地址表的基地址(rva中的序号表)
MOVZX EBX,WORD PTR[EBX+2*EDI]                 
MOV EAX,EBX
MOV EBX,dword ptr[add_b]           ;实际序号
MOV EBX,[EBX+1CH]
ADD EBX,EBP                      
MOV EBX,[EBX+4*EAX]                 
ADD EBX,EBP                        ;实际地址
invoke crt_printf,  addr mesg2, EBX 
ret
.else
JMP second
.endif 

ret
end start

我好快乐,因为我是小熊软糖,小熊软糖(>▽<)!