不能有全局变量 (其实也是使用了绝对地址)
不能使用常量字符串
char szBuffer[] = "ShellCode"; //会使用常量区,所以不可用
//写成
char szBuffer[] = {
'S', 'h', 'e', 'l', '\0'}; //这个使用堆栈
char szBuffer[] = {
'K', '0', 'e', '0', '\0'}; //UNICODE格式,高字节为零,占2个字符,一般函数名为UinCode格式
编写shellcode不能使用绝对地址,因为当我们加载到其他函数中时绝对地址储存的可能什么也没有,甚至是其他函数,所以当我们需要调用一个函数时,需要动态获取函数的地址实现调用。
想要动态获取函数地址,可以使用以下函数
GetProcAddress 从dll中获取函数的地址
LoadLibraryA 将指定的模块加载到调用进程的地址空间中
举个例子:
LPVOID lp = GetProcAddress(LoadLibraryA("user32.dll"),"MessageBoxA");
_asm
{
push 0
push 0
push 0
push 0
call lp
}
这样就可以获取到MessageBoxA函数的地址,并且通过汇编代码实现了调用。
当然如果我们想要在MessageBoxA函数中输出一个字符串的话,可以设置一个字符串指针:
char * pszData =“helloworld”;
并且修改对应的push 参数就可以了。
这种方法可行,但是并不灵活,再看一下更加灵活的方式
用 CreatFileA 函数来演示一下
int entrymain()
{
typedef HANDLE (WINAPI* FN_CreateFileA)(
__in LPCSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in LPSECURITY_ATTRIBUTES lpSecruityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
);
FN_CreatFileA fn_CreateFileA;
fn_CreateFileA = (FN_CreatFileA)GetProcAddress(LoadLibraryA("kernel32.dll"),"CreateFileA");
CreatFileA("hello.txt",GENERIC_WRITE,0,NULL,CREAT_ALWAYS,0,NULL);
}
我们可以自定义一个与想调用的函数一样的新类型,这样我们就可以随便使用,因为这个函数是我们自定义的函数。
当然,明眼的人可能已经发现,我们在使用GetProcAddress函数去获得函数的地址时,GetProcAddress函数本身不就已经是调用的绝对地址了吗?当然LoadLibraryA函数也一样。
这里我们就需要了解一下PEB和TEB与FS寄存器,FS0偏移处是teb结构体,30h偏移处是PEB结构体,而PEB结构体中有三个成员链表分别储存了三个顺序,代码中有详解。通过这三个顺序我们分别可以使用三个方法获得kernel32的基址。获取这个基址的方法还有很多,推荐一篇博客
__declspec(nacked) DWORD getKernel32()
{
__asm
{
mov eax,fs:[30] //fs:[30] 纯存的是PEB,也就是进程环境块,操作系统在加载进程的过程中会自动初始化一个PEB结构体用来初始化该进程的各种信息的结构体
mov eax,[eax+0ch] //也就是PEB 0ch处的偏移,该结构体的三个成员链表都可以获取kernel32的基址
mov eax,[eax+14h] //获取初始化顺序链表的地址,首地址是第一个模块
mov eax,[eax] //第二个模块
mov eax,[eax] //第三个模块
mov eax,[eax+10h] // 10h偏移处就是kernel32的基地址
}
}
看完上面的代码,会有疑惑,为什么是第三个参数呢?看下图,是因为kernel32.dll是第三个被加载的dll文件。
FARPROC _GetProcAddress(HMODULE hModuleBase)
{
PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size){
return NULL;
}
if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
return NULL;
}
PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase +