您的位置:首页 > 运维架构 > Shell

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

2017-11-15 12:03 369 查看
前言:

首先定义两个概念,在一段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方式的鄙见

|[b]************************************************************************[/b]

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


—————————————————————————————————*/

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;                               //------------
aea9
--------------------------- 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


//[b]***************************************************Payload***************************************************[/b]

/*————————————————————————

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();


//[b]***************************************************Payload***************************************************[/b]

/*—————————————————————————————————

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