前面的<<HOOK IAT RING3>>文章中使用到了shellcode,那么这个shellcode是怎么制造出来的呢,本文将为你一步一步的解惑
这个shellcode的主要功能是调用MessageBoxA弹出一个空的对话框,注意此时的地址空间是在别的进程,由于不同的操作系统会影响动
态链接库的加载地址,而且不同版本的dll中函数的偏移量RVA也不尽相同,因此写一个通用型的shellcode就显得非常的有必要
那么shellcode要怎么动态去定位API的地址呢,方法还是一样的,首先定位函数所在的模块,然后在EAT里面进行搜索即可,只要找到
Kernel32.dll中的GetProcAddress和LoadLibraryA的地址就可以通过这两个获得其他模块中函数的地址
注意:网上的很多此类代码并没有通过搜索kernel32.dll模块,而是直接去寻找
Ldr->InInitializationModuleList的第3个模块,这是有问题的,因为从win7开始引入了MinWin的概念导致
InInitializationModuleList中的第三个模块是KernelBase.dll,第四个才是Kernel32.dll,不过
Ldr->InMemoryOrderModuleList中的第三个模块并没有改变还是Kernel32.dll,为了以防万一还是搜索吧,搜索
的时候用的是比较模块的第七个字符是不是’3’来匹配,因为kernel32.dll的第七个字符就是3,这样就可以不用通过计算哈希值来比较
下面贴出内嵌汇编代码,并加了一些注释(winxp,win7x86,win7x64以兼容32位的模式运行,都没问题~)
这个shellcode是我花了一个下午的时间写的,由于是新手,如果下文中有什么纰漏的话欢迎指正!
#include <windows.h>
#include <stdio.h>
void PopMessageBox()
{
__asm{
jmp start
find_function:
push ebp
mov ebp,esp
mov eax,fs:[0x30] //fs points to teb in user mode,get pointer to peb
mov eax,[eax+0x0c] //get peb->ldr
mov eax,[eax+0x14] //get peb->ldr.InMemoryOrderModuleList.Flink(1st entry)
module_loop:
mov eax,[eax] //skip the first entry or get the next entry
mov esi,[eax+0x28] //get the BaseDllName->Buffer
cmp byte ptr [esi+0x0c],’3′ //test the module’s seventh’s wchar is ‘3’ or not,kernel32.dll
jne module_loop
//====================================
//find kernel32.dll module
//====================================
mov eax,[eax+0x10] //LDR_DATA_TABLE_ENTRY->DllBase
//====================================
//kernel32.dll PE Header
//====================================
mov edi,eax
add edi,[edi+0x3c] //IMAGE_DOS_HEADER->e_lfanew
//====================================
//kernel32.dll export directory table
//====================================
mov edi,[edi+0x78] //IMAGE_NT_HEADERS->OptinalHeader.DataDirectory[EAT].VirtualAddress
add edi,eax
mov ebx,edi // ebx is EAT’s virtual address,we’ll use it later
//====================================
//kernel32.dll Name Pointer Table
//====================================
mov edi,[ebx+0x20] //IMAGE_EXPORT_DESCRIPTOR->AddressOfNames RVA
add edi,eax
xor ecx,ecx //NameOrdinals
name_loop:
mov esi,[edi+ecx*4]
add esi,eax
inc ecx
mov edx,[esp+8] //first parameter
cmp dword ptr [esi],edx
jne name_loop
mov edx,[esp+0xc] //second parameter
cmp dword ptr [esi+4],edx
jne name_loop
//======================================
//kernel32.dll Ordinal Table
//======================================
mov edi,[ebx+0x24]
add edi,eax
mov ecx,[edi+ecx*2]
and ecx,0xFFFF //cause ordinal is USHORT of size,so we just use its lower 16-bits
//======================================
//kernel32.dll Address Table
//======================================
mov edi,[ebx+0x1c]
add edi,eax
dec ecx //subtract ordinal base
sal ecx,2
mov edi,[edi+ecx]
add eax,edi
pop ebp
ret 8
start:
//====================================
// Get GetProcAddress’s address
//====================================
push 0x41636f72 //rocA
push 0x50746547 //Getp
call find_function
push eax //store GetProcAddress in stack
//====================================
//Get LoadLibraryA’s address
//====================================
push 0x7262694c //Libr
push 0x64616f4c //Load
call find_function
push eax //store LoadLibraryA in stack
// stack snap
//—————————–high address
// GetProcAddress’s address
//—————————–
// LoadLibraryA’s address <—————–esp
//—————————–low address
//====================================
// Get User32.dll’s image base
//====================================
push 0x3233 //32
push 0x72657375 //user
push esp //lpFileName
call eax //call LoadLibraryA(“user32.dll”)
add esp,8 //cause we push user32 string
//====================================
//Get MessageBox’s address
//====================================
push 0x41786f //oxA
push 0x42656761 //ageB
push 0x7373654d //Mess
push esp //lpProcName
push eax //hModule
call [esp+0x18] //call GetProcAddress(hModule,”MessageBoxA”)
add esp,0xc //cause we push MessageBoxA string
push 0
push 0
push 0
push 0
call eax //call MessagBoxA(0,0,0,0)
add esp,8 //cause we push GetProcAddress and LoadLibrary in stack
}
}
int main()
{
PopMessageBox();
return 0;
}
至于怎么转为shellcode,这里提供一个方法,就是按F10进入VS的调试模式,然后再右键选择查看汇编代码,找到内嵌汇编的开始地址,复制
那个地址处的内容直到内嵌汇编的右大括号,放到十六进制的编辑器中比如NotePad++,然后替换空格为\0x,再稍作修改即可,这里说的比较的模糊,
等有时间的时候再回头过来照顾一下新手吧,先把上面的汇编消化掉~