Shellcode和Payload入门101-超详细源码和注释以及Hex文本
来源:互联网 发布:《unity3d视频教程》 编辑:程序博客网 时间:2024/06/05 08:39
前言:
首先定义两个概念,在一段ShellCode代码中我们可以认为它有两个部分。
ShellCode:用于创建PayLoad环境部分PayLoad :实现需求部分
以下是源代码,OPcode接近400个字节,仅仅完成了MessageBox弹窗,代码有很大的优化空间。
// ShellCode_01.cpp : 定义控制台应用程序的入口点。
//
// Locals —— 局部变量
#define KernalBaseAddr [EBP - 0x4]#define pEAT [EBP - 0x8] #define pENT [EBP - 0xC] #define pEOT [EBP - 0x10] #define PGETPROCADDRESS [EBP - 0x14] #define PLOADLIBRARYA [EBP - 0x18]#define PEXITPROCESS [EBP - 0x1C]#define User32BaseAddr [EBP - 0x20]#define PMESSAGEBOX [EBP - 0x24]
// strRVA —— 字符串寻址
#define wzKERNAL32 [EDX + 0x9]#define szGetProcAddress [EDX + 0x22]#define szLoadLibraryA [EDX + 0x31]#define szExitProcess [EDX + 0x3E]#define szUser32 [EDX + 0x4A]#define szMessageBoxA [EDX + 0x55]#define szGreetings [EDX + 0x61]
// Main
int _tmain(int argc, _TCHAR* argv[]){_asm{ pushad; SUB ESP, 0X60;tag_OEP:
/*—————————————————————————————————
KeyNote
关于在ShellCode中动态获取EIP方法——FSTENV方式
|有时候为了增强ShellCode的健壮性和普遍适用性, 我们会选择动态获取函数来使用,
|而在获取模块地址和函数地址时难免会使用到字符串等常量, 我们很难保证所有的目标程序中都有我们需要的字符串,
|所以我们需要将自己所需要的字符串保存在一个随时能够简单获取的地方, 那这要如何做到呢,
|比较容易想到的一个办法就是将字符串藏到代码里, 然后在代码中通过寻址找到相应的字符串。
|通常的寻址方式无非就是一个基址+一个偏移:
| 一个偏移:在内存中代码就是OPcode, ShellCode也是16进制的数据, 这些16进制数据加载到内存中和在文件中的相对位置是不变的,
| 可以理解为ShellCode中任意一个字节相对另外一个字节的值在文件中和在内存中是一样的,
| 那么我们就可以手动算出这个值, 作为某个数据相对于某个位置的偏移。
| 一个基址:本项目的第一个难点就在于动态获取一个基址即EIP, 即某代码字节在内存中的地址, 我们可以动态获取一个地址, 生成好文件后,
| 查看项目的OPcode来计算出字符串相对基址的偏移, 然后就可以获取到字符串的首地址了。
|动态获取一个EIP的方法有几种, 均来自于前辈们的心血, 而且大多看似很简单, 却不失精妙, 简单的几个字节, 就体现了前辈们思维的锐利。
|我这里使用的是稍显不寻常的方法, 希望能够应变某些复杂一点的环境, 下面为大家讲述一下我对FSTENV方式的鄙见
|************************************************************************
|FSTENV是一个汇编指令, CPU用其记录最后一条浮点数指令的环境到内存中, 其中就包括了这条指令的EIP
|那么步骤便是:
|1.操作浮点数
|2.保存环境到栈中
|3.保存EIP
|NOTE: 下面使用 FNSTENV[ESP - 0xc], 因这条指令保存的是一个结构体, 而我们所需要的EIP是第4个
| 元素, 将这个结构体从[ESP - 0xc]开始PUSH, 那么这条指令执行完后, ESP指向的便是我们所需
| 要的数据, 所以下一条汇编只需一个简单的POP即可获得我们梦寐以求的人生的位置, 哦不, 是
| ShellCode的位置, 而通往目标程序心脏的钥匙就在你手中。
—————————————————————————————————*/
// GetPC —— 动态获取ShellCode起始位置
FLDZ; // | ShellCodeBase FNSTENV[ESP - 0xc]; // | POP EDX; // | EDX == ShellCodeBase JMP tag_shellcode; // |->0x9 bytes
// .rdata —— ShellCode全局变量
#pragma region CHAR*&WCHAR* // Data Section VA : [ShellCodeBase + 0x9] // L"KERNAL32.DLL" [EDX + 0x9] _asm _emit(0x4b)_asm _emit(0x00)_asm _emit(0x45)_asm _emit(0x00) _asm _emit(0x52)_asm _emit(0x00)_asm _emit(0x4e)_asm _emit(0x00) _asm _emit(0x45)_asm _emit(0x00)_asm _emit(0x4c)_asm _emit(0x00) _asm _emit(0x33)_asm _emit(0x00)_asm _emit(0x32)_asm _emit(0x00) _asm _emit(0x2e)_asm _emit(0x00)_asm _emit(0x44)_asm _emit(0x00) _asm _emit(0x4c)_asm _emit(0x00)_asm _emit(0x4c)_asm _emit(0x00) _asm _emit(0x00) // 0x19 bytes // "GetProcAddress" [EDX + 0x22] _asm _emit(0x47)_asm _emit(0x65)_asm _emit(0x74)_asm _emit(0x50) _asm _emit(0x72)_asm _emit(0x6f)_asm _emit(0x63)_asm _emit(0x41) _asm _emit(0x64)_asm _emit(0x64)_asm _emit(0x72)_asm _emit(0x65) _asm _emit(0x73)_asm _emit(0x73)_asm _emit(0x00) // 0xF bytes // "LoadLibraryA" [EDX + 0x31] _asm _emit(0x4c)_asm _emit(0x6f)_asm _emit(0x61)_asm _emit(0x64) _asm _emit(0x4c)_asm _emit(0x69)_asm _emit(0x62)_asm _emit(0x72) _asm _emit(0x61)_asm _emit(0x72)_asm _emit(0x79)_asm _emit(0x41) _asm _emit(0x00) // 0xD bytes // "ExitProcess" [EDX + 0x3E] _asm _emit(0x45)_asm _emit(0x78)_asm _emit(0x69)_asm _emit(0x74) _asm _emit(0x50)_asm _emit(0x72)_asm _emit(0x6F)_asm _emit(0x63) _asm _emit(0x65)_asm _emit(0x73)_asm _emit(0x73)_asm _emit(0x00)// 0xC bytes // "User32.dll" [EDX + 0x4A] _asm _emit(0x55)_asm _emit(0x73)_asm _emit(0x65)_asm _emit(0x72) _asm _emit(0x33)_asm _emit(0x32)_asm _emit(0x2e)_asm _emit(0x64) _asm _emit(0x6c)_asm _emit(0x6c)_asm _emit(0x00) // 0xB bytes // "MessageBoxA" [EDX + 0x55] _asm _emit(0x4D)_asm _emit(0x65)_asm _emit(0x73)_asm _emit(0x73) _asm _emit(0x61)_asm _emit(0x67)_asm _emit(0x65)_asm _emit(0x42) _asm _emit(0x6F)_asm _emit(0x78)_asm _emit(0x41)_asm _emit(0x00)// 0xC bytes // "Hello 15PB" [EDX + 0x61] _asm _emit(0x48)_asm _emit(0x65)_asm _emit(0x6C)_asm _emit(0x6C) _asm _emit(0x6F)_asm _emit(0x20)_asm _emit(0x31)_asm _emit(0x35) _asm _emit(0x50)_asm _emit(0x42)_asm _emit(0x20)_asm _emit(0x00)// 0xC bytes#pragma endregion CHAR*&WCHAR*
/*—————————————————————————————————
GetModuleBase —— 获取Kernal32.dll基址
Ldr _PEB_LDR_DATA
InLoadOrderModuleList _List_ENTRY
_LIST_ENTRY{
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
}
_List_ENTRY地址即(_LIST_ENTRY+0x000 Flink)前一个_LDR_DATA_TABLE_ENTRY地址
_LDR_DATA_TABLE_ENTRY第一个元素即_List_ENTRY
_List_ENTRY前移1次到ntdll
_List_ENTRY前移2次到Kernel32
—————————————————————————————————*/
tag_shellcode: MOV EAX, FS:[0x30]; // EAX == _PEB MOV EAX, [EAX + 0xC]; // EAX == Ldr _PEB_LDR_DATA MOV EAX, [EAX + 0xC]; // EAX == _List_ENTRY == _LDR_DATA_TABLE_ENTRY JMP tag_checkname;tag_nextModule: MOV EAX, [EAX]; // _LIST_ENTRY == _LIST_ENTRY->(+0x000)Flink == Previous _LDR_DATA_TABLE_ENTRY Addrtag_checkname: MOV EBX, DWORD PTR DS : [EAX + 0x2C + 0x4]; // _UNICODE_STRING->BUFFER PUSH EAX; // Save List Addr MOV EAX, DWORD PTR DS : [EAX + 0x2C]; // _UNICODE_STRING->Length(word) AND EAX, 0X0000FFFF; // Save Loword : Length(word) SHR EAX, 2; // Length*2 == bytes MOV ECX, EAX; // rep cmps times MOV ESI, EBX; // POP EAX; // EAX == _List_ENTRY LEA EDI, wzKERNAL32; // Module Name in UNICODE L"KERNAL32.DLL" REP CMPS; // JNZ tag_nextModule; // MOV EAX, DWORD PTR DS : [EAX + 0x18]; // _LDR_DATA_TABLE_ENTRY->DllBase MOV KernalBaseAddr, EAX; // [EBP-0x4]:PVOID KernalBaseAddr PUSH EAX;
/*—————————————————————————————————
Get
pEAT
pENT
pEOT
—— 获取导出表数据
Source c code :
typedef FARPROC(WINAPI *GETPROCADDR)(HMODULE hModule, LPCSTR lpProcName);typedef HMODULE(WINAPI *LOADLIBRARYA)(_In_ LPCSTR lpName);GETPROCADDR g_getprocaddr;LOADLIBRARYA g_loadlibA;CHAR* ModuleBuf = (CHAR*)KernalBaseAddr;PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ModuleBuf;PIMAGE_NT_HEADERS pNT = PIMAGE_NT_HEADERS(pDos->e_lfanew + ModuleBuf);PIMAGE_OPTIONAL_HEADER pOpt = &pNT->OptionalHeader;PIMAGE_DATA_DIRECTORY pExportDir = pOpt->DataDirectory + 0;PIMAGE_EXPORT_DIRECTORY pExport = PIMAGE_EXPORT_DIRECTORY(pExportDir->VirtualAddress + ModuleBuf);PDWORD pEAT = PDWORD(pExport->AddressOfFunctions + ModuleBuf);PDWORD pENT = PDWORD(pExport->AddressOfNames + ModuleBuf);PWORD pEOT = PWORD(pExport->AddressOfNameOrdinals + ModuleBuf);DWORD NumONames = pExport->NumberOfNames;
—————————————————————————————————*/
MOV EAX, [EAX + 0x3C]; // | pDosHeader->e_lfanew ADD EAX, KernalBaseAddr; // |== pNTHeaderpDosHeader->e_lfanew + KernalBaseAddr LEA EAX, [EAX + 0x18]; // &pNTHeader->OptionalHeader MOV EAX, [EAX + 0x60]; // OptionalHeader->DataDirectory->(+0x0)VirtualAddress ADD EAX, KernalBaseAddr; // pExportDir = VirtualAddress + KernalBaseAddr POP ESI; // KernalBaseAddr MOV EBX, [EAX + 0x1C]; // | pExportDir->AddressOfFunction MOV pEAT, ESI; // | + KernalBaseAddr ADD pEAT, EBX; // |== [EBP-0x8]:PDWORD pEAT MOV EBX, [EAX + 0x20]; // | pExportDir->AddressOfNames MOV pENT, ESI; // | + KernalBaseAddr ADD pENT, EBX; // |== [EBP-0xC]:PDWORD pENT MOV EBX, [EAX + 0x24]; // | pExportDir->AddressOfNameOrdinals MOV pEOT, ESI; // | + KernalBaseAddr ADD pEOT, EBX; // |==[EBP-0x10]:PWORD pEOT MOV ECX, [EAX + 0x18]; // DOWRD NumerOfNames
/*—————————————————————————————————
Get
GetProcAddress();
LoadLibraryA();
ExitProcess();
—— 获取关键函数地址
source c code :
for (INT i = 0; i < NumONames; ++i) { CHAR* pName = pENT[i] + ModuleBuf; if (strcmp(pName, getProcAddr) == 0) { g_getprocaddr = GETPROCADDR(pEAT[pEOT[i]] + (DWORD)ModuleBuf); g_loadlibA = LOADLIBRARYA(g_getprocaddr((HMODULE)ModuleBuf, loadLibA)); break; } }
—————————————————————————————————*/
XOR EAX, EAX; // INT i(EAX)= 0;loop_EXT: CMP EAX, ECX; // EAX < ECX(NumerOfNames) JNB tag_elfin; // PUSH EAX; // SHL EAX, 2; // | EAX * 4 MOV EDI, pENT; // | pENT ADD EDI, EAX; // | &pENT[EAX] == pENT + EAX*4 MOV EDI, [EDI]; // | pENT[EAX] ADD EDI, ESI; // |== szName == pENT[EAX](RVA)+KernalBaseAddr PUSH ESI; // + KernalBaseAddr LEA ESI, szGetProcAddress; // [EDX + 0x22] "GetProcAddress" PUSH ECX; MOV ECX, 0xF; // Length Of sz"GetProcAddress" rep cmps; // strcmp(szName, "GetProcAddress") POP ECX; // | POP ESI; // | POP EAX; // |->跳转与否均需用到,提前POP JZ tag_foundproc; // if(strcmp()==0) JMP tag_foundproc INC EAX; // ++i(EAX); JMP loop_EXT; //tag_foundproc: // MOV ECX, pEOT; // | [EBP-0x10]:PWORD pEOT SHL EAX, 1; // | EAX * 2 (PWORD pEOT) ADD ECX, EAX; // | &pEOT[pENT] MOV CX, WORD PTR[ECX]; // |== pEOT[pENT] AND ECX, 0x0000ffff; // Save Loword SHL ECX, 2; // | ECX * 4 (PDWORD pEAT) MOV EAX, pEAT; // | EAX == pEAT[0] ADD EAX, ECX; // |==pEAT[ECX] == pEAT[0] + ECX MOV EAX, [EAX]; // ADD EAX, ESI; // + KernalBaseAddr MOV PGETPROCADDRESS, EAX; // [EBP - 0x54]:GetProcAddress();
/*————————————————————————
LoadLibraryA = GetProcAddress(&Kernal32.dll, “LoadLibraryA”);
————————————————————————*/
PUSH EDX; //--------------------------------------- GetProcAddress() Changes EDX LEA ECX, szLoadLibraryA; // |-&"LoadLibraryA" PUSH ECX; // |-&"LoadLibraryA" LPCSTR lpProcName PUSH ESI; // |-&Kernal32.dll HMODULE hModule CALL PGETPROCADDRESS; // |->CALL GetProcAddress(); MOV PLOADLIBRARYA, EAX; // POP EDX; // Resume EDX
/*————————————————————————
ExitProcess = GetProcAddress(&Kernal32.dll, “ExitProcess”);
————————————————————————*/
PUSH EDX; //--------------------------------------- GetProcAddress() Changes EDX LEA ECX, szExitProcess; // &"ExitProcess" PUSH ECX; // |-&"ExitProcess" LPCSTR lpProcName PUSH ESI; // |-&Kernal32.dll HMODULE hModule CALL PGETPROCADDRESS; // |->GetProcAddress(); MOV PEXITPROCESS, EAX; // ExitProcess = RetVal POP EDX; // Resume EDX
//***************************************************Payload***************************************************
/*————————————————————————
MessageBoxA = GetProcAddress(LoadLibraryA(“User32.dll”), “MessageBoxA”);
————————————————————————*/
PUSH EDX; //--------------------------------------- LoadLibraryA() Changes EDX LEA ECX, szUser32; // &"User32.dll" PUSH ECX; // |-&"User32.dll" LPCSTR lpLibFileName CALL PLOADLIBRARYA; // |->LoadLibraryA(); MOV User32BaseAddr, EAX; // User32BaseAddr = RetVal POP EDX; // Resume EDX PUSH EDX; //--------------------------------------- GetProcAddress() Changes EDX LEA ECX, szMessageBoxA; // | &"MessageBoxA" PUSH ECX; // |-&"MessageBoxA" LPCSTR lpProcName PUSH EAX; // |-&User32.dll HMODULE hModule CALL PGETPROCADDRESS; // |->GetProcAddress(); MOV PMESSAGEBOX, EAX; // MessageBoxA = RetVal POP EDX; // Resume EDX
/*————————————————————————
MessageBoxA(NULL, “Hello 15PB”, “Hello 15PB”, NULL);
————————————————————————*/
LEA ECX, szGreetings; // &"Hello 15PB" XOR EBX, EBX; // EBX == 0(NULL) PUSH EBX; // |-NULL HWND hWnd, PUSH ECX; // |-&"Hello 15PB" LPCSTR lpText, PUSH ECX; // |-&"Hello 15PB" LPCSTR lpCaption, PUSH EBX; // |-NULL UINT uType CALL PMESSAGEBOX; // |->MessageBoxA();
//***************************************************Payload***************************************************
/*—————————————————————————————————
ExitProcess(NULL);
—————————————————————————————————*/
tag_Exit: // XOR EBX, EBX; // EBX == 0 PUSH EBX; // |-NULL UINT uExitCode CALL PEXITPROCESS; // |->ExitProcess();
/*—————————————————————————————————
Reserved
—————————————————————————————————*/
tag_elfin: add ESP, 0X5C; popad; } return 0;}
附:以上ShellCode的Hex形态
// ShellCode_Hex_01.cpp : 定义控制台应用程序的入口点。char ShellCode_Hex_01[] = "\x55\x8B\xEC\x53\x56\x57\x60\x83\xEC\x60\xD9\xEE\xD9\x74\x24\xF4\x5A\xEB\x64\x4B\x00\x45\x00\x52\x00\x4E\x00\x45\x00\x4C\x00\x33""\x00\x32\x00\x2E\x00\x44\x00\x4C\x00\x4C\x00\x00\x47\x65\x74\x50\x72\x6F\x63\x41\x64\x64\x72\x65\x73\x73\x00\x4C\x6F\x61\x64\x4C""\x69\x62\x72\x61\x72\x79\x41\x00\x55\x73\x65\x72\x33\x32\x2E\x64\x6C\x6C\x00\x4D\x65\x73\x73\x61\x67\x65\x42\x6F\x78\x41\x00\x48""\x65\x6C\x6C\x6F\x20\x31\x35\x50\x42\x20\x00\x45\x78\x69\x74\x50\x72\x6F\x63\x65\x73\x73\x00\x64\xA1\x30\x00\x00\x00\x8B\x40\x0C""\x8B\x40\x0C\xEB\x02\x8B\x00\x3E\x8B\x58\x30\x50\x3E\x8B\x40\x2C\x25\xFF\xFF\x00\x00\xC1\xE8\x02\x8B\xC8\x8B\xF3\x58\x8D\x7A\x09""\xF3\xA6\x75\xE1\x3E\x8B\x40\x18\x89\x45\xFC\x50\x8B\x40\x3C\x03\x45\xFC\x8D\x40\x18\x8B\x40\x60\x03\x45\xFC\x5E\x8B\x58\x1C\x89""\x75\xF8\x01\x5D\xF8\x8B\x58\x20\x89\x75\xF4\x01\x5D\xF4\x8B\x58\x24\x89\x75\xF0\x01\x5D\xF0\x8B\x48\x18\x33\xC0\x3B\xC1\x0F\x83""\x85\x00\x00\x00\x50\xC1\xE0\x02\x8B\x7D\xF4\x03\xF8\x8B\x3F\x03\xFE\x56\x8D\x72\x22\x51\xB9\x0F\x00\x00\x00\xF3\xA6\x59\x5E\x58""\x74\x03\x40\xEB\xD7\x8B\x4D\xF0\xD1\xE0\x03\xC8\x66\x8B\x09\x81\xE1\xFF\xFF\x00\x00\xC1\xE1\x02\x8B\x45\xF8\x03\xC1\x8B\x00\x03""\xC6\x89\x45\xEC\x52\x8D\x4A\x31\x51\x56\xFF\x55\xEC\x89\x45\xE8\x5A\x52\x8D\x4A\x61\x51\x56\xFF\x55\xEC\x89\x45\xDC\x5A\x52\x8D""\x4A\x3E\x51\xFF\x55\xE8\x89\x45\xE4\x5A\x52\x8D\x4A\x49\x51\x50\xFF\x55\xEC\x89\x45\xE0\x5A\x8D\x4A\x55\x33\xDB\x53\x51\x51\x53""\xFF\x55\xE0\x33\xDB\x53\xFF\x55\xDC";int _tmain(int argc, _TCHAR* argv[]){_asm{ LEA EAX, ShellCode_Hex_01; push EAX; RETN;}return 0;}
注:
- Shellcode和Payload入门101-超详细源码和注释以及Hex文本
- Shellcode和Payload入门102-代码中的加密-一如既往地源码和超详细注释
- 超详细设置Idea类注释模板和方法注释模板
- 决策树基本理论学习以及Python代码实现和详细注释
- linux内核工作队列讲解和源码详细注释
- 超详细ofstream和ifstream详细用法
- 单行注释和多行注释 文本注释
- Redis源码剖析和注释(二十二)--- Redis 复制(replicate)源码详细解析
- SSM超详细搭建教程(Spring+SpringMVC+Mybatis)以及集成Redis和Druid
- C#HttpHelper万能采集类源码和使用案例【超详细傻瓜式采集】
- GBDT源码分析和注释
- Ajax入门实例----HelloWorld附源码详细注释
- Ajax入门实例----HelloWorld附源码详细注释
- git入门,超详细。
- webpack 入门,超详细
- Uiautomator自动化测试编写和调试---小白入门超详细
- request payload和form data
- hashset的应用及注意事项,以及案例分析和详细注释
- 字符串 转变成数字
- 导入orcale数据库
- Mysql启动报错:Unit mysql.service failed to load: No such file or directory的解决办法
- PullToRefresh下拉和上拉简单实现
- Java性能优化之JVM GC(垃圾回收机制)
- Shellcode和Payload入门101-超详细源码和注释以及Hex文本
- jQuery获取表格 复选框被选中一行的所有列数据
- html元素超出隐藏不换行
- javascript demo简单示例代码
- MySQL Docker镜像配置主从
- 反射的初步了解
- Mean Average Precision vs Mean Reciprocal Rank
- Android实现底部导航栏
- 树的应用之树的同构