Shellcode和Payload入门101-超详细源码和注释以及Hex文本

Shellcode和Payload⼊门101-超详细源码和注释以及Hex⽂本前⾔:
⾸先定义两个概念,在⼀段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 Addr tag_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;
}
}
—————————————————————————————————*/

本文发布于:2024-09-20 19:53:42,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/549772.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:获取   字符串   内存   地址   动态   字节
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议