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;}

注:

阅读全文
0 0
原创粉丝点击