}
// 生成外壳程序命令行
char *PrepareShellExe(char *CmdParam, unsigned long BaseAddr, unsigned long ImageSize) { if(IsNT()) {
char *Buf = new char[256]; memset(Buf, 0, 256);
GetModuleFileName(0, Buf, 256); strcat(Buf, CmdParam); return Buf; // 请记得释放内存;-) } else {
// Win98下的处理请参考原文;-)
// http://community.csdn.net/Expert/topic/4416/4416252.xml?temp=8.709133E-03 return NULL; } }
// 是否包含可重定向列表
BOOL HasRelocationTable(PIMAGE_NT_HEADERS peH) {
return (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) && (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); }
#pragma pack(push, 1) typedef struct{
unsigned long VirtualAddress; unsigned long SizeOfBlock; } *PImageBaseRelocation; #pragma pack(pop)
// 重定向PE用到的地址
void DoRelocation(PIMAGE_NT_HEADERS peH, void *OldBase, void *NewBase) {
unsigned long Delta = (unsigned long)NewBase - peH->OptionalHeader.ImageBase; PImageBaseRelocation p = (PImageBaseRelocation)((unsigned long)OldBase
+ peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); while(p->VirtualAddress + p->SizeOfBlock) {
unsigned short *pw = (unsigned short *)((int)p + sizeof(*p)); for(unsigned int i=1; i <= (p->SizeOfBlock - sizeof(*p)) / 2; ++i) {
if((*pw) & 0xF000 == 0x3000){
unsigned long *t = (unsigned long *)((unsigned long)(OldBase) + p->VirtualAddress + ((*pw) & 0x0FFF)); *t += Delta; } ++pw; }
p = (PImageBaseRelocation)pw; } }
// 卸载原外壳占用内存
BOOL UnloadShell(HANDLE ProcHnd, unsigned long BaseAddr) {
typedef unsigned long (__stdcall *pfZwUnmapViewOfSection)(unsigned long, unsigned long); pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL; BOOL res = FALSE;
HMODULE m = LoadLibrary(\
if(m){
ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(m, \ if(ZwUnmapViewOfSection)
res = (ZwUnmapViewOfSection((unsigned long)ProcHnd, BaseAddr) == 0); FreeLibrary(m); }
return res; }
// 创建外壳进程并获取其基址、大小和当前运行状态
BOOL CreateChild(char *Cmd, CONTEXT &Ctx, HANDLE &ProcHnd, HANDLE &ThrdHnd, unsigned long &ProcId, unsigned long &BaseAddr, unsigned long &ImageSize) {
STARTUPINFOA si;
PROCESS_INFORMATION pi; unsigned long old;
MEMORY_BASIC_INFORMATION MemInfo; memset(&si, 0, sizeof(si)); memset(&pi, 0, sizeof(pi)); si.cb = sizeof(si);
BOOL res = CreateProcess(NULL, Cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); // 以挂起方式运行进程; if(res){
ProcHnd = pi.hProcess; ThrdHnd = pi.hThread; ProcId = pi.dwProcessId;
// 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址 Ctx.ContextFlags = CONTEXT_FULL; GetThreadContext(ThrdHnd, &Ctx);
ReadProcessMemory(ProcHnd, (void *)(Ctx.Ebx+8), &BaseAddr, sizeof(unsigned long), &old); // 读取加载基址 void *p = (void *)BaseAddr; // 计算外壳进程占有的内存
while(VirtualQueryEx(ProcHnd, p, &MemInfo, sizeof(MemInfo)))
{
if(MemInfo.State = MEM_FREE) break;
p = (void *)((unsigned long)p + MemInfo.RegionSize); }
ImageSize = (unsigned long)p - (unsigned long)BaseAddr; }
return res; }
// 创建外壳进程并用目标进程替换它然后执行
HANDLE AttachPE(char *CmdParam, PIMAGE_NT_HEADERS peH, PIMAGE_SECTION_HEADERS peSecH, void *Ptr, unsigned long ImageSize, unsigned long &ProcId) {
HANDLE res = INVALID_HANDLE_VALUE; CONTEXT Ctx; HANDLE Thrd;
unsigned long Addr, Size;
char *s = PrepareShellExe(CmdParam, peH->OptionalHeader.ImageBase, ImageSize); if(s==NULL) return res;
if(CreateChild(s, Ctx, res, Thrd, ProcId, Addr, Size)){ void *p = NULL; unsigned long old;
if((peH->OptionalHeader.ImageBase == Addr) && (Size >= ImageSize)){// 外壳进程可以容纳目标进程并且加载地址一致 p = (void *)Addr;
VirtualProtectEx(res, p, Size, PAGE_EXECUTE_READWRITE, &old); }
else if(IsNT()){
if(UnloadShell(res, Addr)){// 卸载外壳进程占有内存
p = MyVirtualAllocEx((unsigned long)res, (void *)peH->OptionalHeader.ImageBase, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
if((p == NULL) && HasRelocationTable(peH)){// 分配内存失败并且目标进程支持重定向
p = MyVirtualAllocEx((unsigned long)res, NULL, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(p) DoRelocation(peH, Ptr, p); // 重定向 } } if(p){
WriteProcessMemory(res, (void *)(Ctx.Ebx+8), &p, sizeof(DWORD), &old); // 重置目标进程运行环境中的基址 peH->OptionalHeader.ImageBase = (unsigned long)p;
if(WriteProcessMemory(res, p, Ptr, ImageSize, &old)){// 复制PE数据到目标进程 Ctx.ContextFlags = CONTEXT_FULL; if((unsigned long)p == Addr)
Ctx.Eax = peH->OptionalHeader.ImageBase + peH->OptionalHeader.AddressOfEntryPoint; // 重置运行环境中的入口地址 else
Ctx.Eax = (unsigned long)p + peH->OptionalHeader.AddressOfEntryPoint; SetThreadContext(Thrd, &Ctx);// 更新运行环境 ResumeThread(Thrd);// 执行 CloseHandle(Thrd); }
else{// 加载失败,杀掉外壳进程 TerminateProcess(res, 0); CloseHandle(Thrd); CloseHandle(res);
res = INVALID_HANDLE_VALUE; } }
else{// 加载失败,杀掉外壳进程 TerminateProcess(res, 0); CloseHandle(Thrd); CloseHandle(res);
res = INVALID_HANDLE_VALUE; } }
delete[] s; return res; }