X32进程注入x64DLL到x64进程

在x32程序中获得x64函数地址是找到这个项目,之后根据自己的理解稍微改了改代码,测试之后能够正常的注入,代码如下

#include "stdafx.h"
#include "x32Injectx64.h"
#include <Windows.h>
#include "wow64ext.h"

#pragma comment(lib,"wow64ext.lib")

CWinApp theApp;

using namespace std;

typedef struct _UNICODE_STRING {
	USHORT    Length;    
	USHORT	  MaximumLength; 
	DWORD64   Buffer;     
} UNICODE_STRING ,*PUNICODE_STRING;



//这里是返回到x32模式
char RetFar[10] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00 };

UCHAR Code[] = {
		0x48, 0x83, 0xEC, 0x28,                 // sub rsp, 0x28   ,第一个是48,这里改为cc方便调试
		0x48, 0x31, 0xC9,                       // xor rcx, rcx
		0x48, 0x31, 0xD2,                       // xor rdx, rdx
		0x49, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,     // mov r8, ModuleFileName   offset +12
		0x49, 0xB9, 0, 0, 0, 0, 0, 0, 0, 0,     // mov r9, ModuleHandle     offset +22
		0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,     // mov rax, LdrLoadDll      offset +32
		0xFF, 0xD0,                             // call rax
		0x48, 0x83, 0xC4, 0x28,                 // add rsp, 0x28

		0xC3                                 // ret   //如果是32位需要将这里返回为32位状态,64位用它
		
		/*0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,    // mov rax, RetFar    offset+48

		0x48, 0x8B, 0x0C, 0x24,                //  mov rcx,qword ptr ss : [rsp]  
		0x48, 0x89, 0x08,                      //  mov qword ptr ds : [rax],rcx  

		0x48,0xff,0x28                         //jmp far tword ptr ds:[rax] */       
};

UCHAR code32To64[] = {
	0xea,0x00,0x10,0x40, 0x00,0x33,0x00   //jmp 33:401000 ea

};

enum  InjectResult{
	OK,
	Error_NoSuchFile,
	Error_OpenProcess,
	Error_VirtualAllocEx,
	Error_GetProcAddress,
	Error_WriteProcessMemory,
	Error_CreateRemoteThread
};

InjectResult Wow64Injectx64(DWORD processid, const TCHAR* file_path) {

	if (!PathFileExists(file_path)) {
		return Error_NoSuchFile;
	}

	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processid);
	if (INVALID_HANDLE_VALUE == handle) {
		return Error_OpenProcess;
	}

	size_t file_path_mem_length = (size_t)::_tcslen(file_path) +1;
	size_t paramemter_size = file_path_mem_length  * sizeof(TCHAR) + sizeof(UNICODE_STRING) + sizeof(DWORD64) ;//申请的大小
	DWORD64 paramemter_mem_addr = (DWORD64)VirtualAllocEx64(handle, NULL, paramemter_size, MEM_COMMIT, PAGE_READWRITE);//目标地址
	DWORD64  shell_code_addr = (DWORD64)VirtualAllocEx64(handle, NULL, sizeof(Code), MEM_COMMIT, PAGE_EXECUTE_READWRITE);//申请的shellcode的大小是多少
	DWORD64  shell_code_32 = (DWORD64)VirtualAllocEx64(handle, NULL, sizeof(shell_code_32), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	DWORD64  ret_32 = (DWORD64)VirtualAllocEx64(handle, NULL, sizeof(RetFar), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	if ((!paramemter_mem_addr) || (!shell_code_addr)) {
		return Error_VirtualAllocEx;
	}

	DWORD64 ntdll64 = GetModuleHandle64(L"ntdll.dll");
	DWORD64 ntdll_LdrLoadDll = GetProcAddress64(ntdll64, "LdrLoadDll");
	DWORD64 ntdll_RtlCreateUserThread = GetProcAddress64(ntdll64, "RtlCreateUserThread");
	DWORD64 ntdll_RtlExitThread = GetProcAddress64(ntdll64, "RtlExitUserThread");
	if (NULL == ntdll_LdrLoadDll || NULL == ntdll_RtlCreateUserThread || NULL == ntdll_RtlExitThread) {
		return Error_GetProcAddress;
	}


	// Fill stubs
	*(ULONGLONG*)((PUCHAR)Code + 12) = paramemter_mem_addr + 8;//第二个参数放到是paramemter_mem_addr+0x10
	*(ULONGLONG*)((PUCHAR)Code + 22) = paramemter_mem_addr;//第一个参数放到是句柄
	*(ULONGLONG*)((PUCHAR)Code + 32) = ntdll_LdrLoadDll;
	//*(ULONGLONG*)((PUCHAR)Code + 48) = ret_32;

	//*(ULONG*)((PUCHAR)code32To64+1) = shell_code_addr;


	file_path_mem_length *= 2;//最大为多大
	DWORD tmpSize = file_path_mem_length - 2;//当前字符串的大小
	DWORD64 address = paramemter_mem_addr + 0x18;
	if (!WriteProcessMemory64(handle, paramemter_mem_addr + 8, &tmpSize, 2, NULL) ||
		!WriteProcessMemory64(handle, paramemter_mem_addr + 10, &file_path_mem_length, 2, NULL) ||
		!WriteProcessMemory64(handle, paramemter_mem_addr + 0x10, &address, 8, NULL) ||//记录的字符串的地址,这里不是以12开始是因为8字节对齐,
		!WriteProcessMemory64(handle, paramemter_mem_addr + 0x18, (LPVOID)file_path, (size_t)::_tcslen(file_path) * sizeof(TCHAR), NULL) ||
		!WriteProcessMemory64(handle, shell_code_addr, Code, sizeof(Code), NULL)||
		!WriteProcessMemory64(handle, shell_code_32, code32To64, sizeof(code32To64), NULL)||
		!WriteProcessMemory64(handle, ret_32, RetFar, sizeof(RetFar), NULL)
		) {
		return Error_WriteProcessMemory;
	}
	DWORD64 hRemoteThread = 0;
	struct {
		DWORD64 UniqueProcess;
		DWORD64 UniqueThread;
	} client_id;
	DWORD64 a = X64Call(ntdll_RtlCreateUserThread, 10,
		(DWORD64)handle,					// ProcessHandle
		(DWORD64)NULL,                      // SecurityDescriptor
		(DWORD64)FALSE,                     // CreateSuspended
		(DWORD64)0,                         // StackZeroBits
		(DWORD64)NULL,                      // StackReserved
		(DWORD64)NULL,                      // StackCommit
		shell_code_addr,					// StartAddress,如果是注入64位进程把这里改为shell_code_addr就行
		(DWORD64)NULL,                      // StartParameter
		(DWORD64)&hRemoteThread,            // ThreadHandle
		(DWORD64)&client_id);               // ClientID)//
	if (INVALID_HANDLE_VALUE == (HANDLE)hRemoteThread) {
		return Error_CreateRemoteThread;
	}
	return OK;
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){
	cout<<"What ID You Want To Inject"<<endl;   
	ULONG_PTR ProcessID = 0;
	
	printf("Input ProcessID\r\n");
	cin>>ProcessID;
	WCHAR file_path[] = L"C:\\64.dll";

	
	if (OK==Wow64Injectx64(ProcessID,file_path)){
		printf("Inject Success!\n");
	}
	return 0;
}


这里又引发了一个问题,就是既然是通过切换cs的方式加载的dll,那么x32能不能加载x64的dll,于是把上面的代码改了改,主要是这部分的改动。

由于启动线程之后当前的状态是x32模式下的,所以使用远跳切换cs,后面的401000不是固定,是根据后面申请的地址填的,最后当我们加载dll之后在把当前的cs给改回来(这里不改回来程序会崩掉),之后测试。最后的测试结果是不行,按照正常的理解也是不行了,如果加载导出函数,那么解析的时候是根据x32去解析x64的代码肯定是会出现问题的,有兴趣的朋友可以去试一下。改了之后的代码如下。



//这里是返回到x32模式
char RetFar[10] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00 };

UCHAR Code[] = {
		0x48, 0x83, 0xEC, 0x28,                 // sub rsp, 0x28   ,第一个是48,这里改为cc方便调试
		0x48, 0x31, 0xC9,                       // xor rcx, rcx
		0x48, 0x31, 0xD2,                       // xor rdx, rdx
		0x49, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,     // mov r8, ModuleFileName   offset +12
		0x49, 0xB9, 0, 0, 0, 0, 0, 0, 0, 0,     // mov r9, ModuleHandle     offset +22
		0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,     // mov rax, LdrLoadDll      offset +32
		0xFF, 0xD0,                             // call rax
		0x48, 0x83, 0xC4, 0x28,                 // add rsp, 0x28

		//0xC3                                 // ret   //如果是32位需要将这里返回为32位状态,64位用它
		
		0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,    // mov rax, RetFar    offset+48

		0x48, 0x8B, 0x0C, 0x24,                //  mov rcx,qword ptr ss : [rsp]  
		0x48, 0x89, 0x08,                      //  mov qword ptr ds : [rax],rcx  

		0x48,0xff,0x28                         //jmp far tword ptr ds:[rax]       
};

UCHAR code32To64[] = {
	0xea,0x00,0x10,0x40, 0x00,0x33,0x00   //jmp 33:401000 ea

};

enum  InjectResult{
	OK,
	Error_NoSuchFile,
	Error_OpenProcess,
	Error_VirtualAllocEx,
	Error_GetProcAddress,
	Error_WriteProcessMemory,
	Error_CreateRemoteThread
};

InjectResult Wow64Injectx64(DWORD processid, const TCHAR* file_path) {

	if (!PathFileExists(file_path)) {
		return Error_NoSuchFile;
	}

	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processid);
	if (INVALID_HANDLE_VALUE == handle) {
		return Error_OpenProcess;
	}

	size_t file_path_mem_length = (size_t)::_tcslen(file_path) +1;
	size_t paramemter_size = file_path_mem_length  * sizeof(TCHAR) + sizeof(UNICODE_STRING) + sizeof(DWORD64) ;//申请的大小
	DWORD64 paramemter_mem_addr = (DWORD64)VirtualAllocEx64(handle, NULL, paramemter_size, MEM_COMMIT, PAGE_READWRITE);//目标地址
	DWORD64  shell_code_addr = (DWORD64)VirtualAllocEx64(handle, NULL, sizeof(Code), MEM_COMMIT, PAGE_EXECUTE_READWRITE);//申请的shellcode的大小是多少
	DWORD64  shell_code_32 = (DWORD64)VirtualAllocEx64(handle, NULL, sizeof(shell_code_32), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	DWORD64  ret_32 = (DWORD64)VirtualAllocEx64(handle, NULL, sizeof(RetFar), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	if ((!paramemter_mem_addr) || (!shell_code_addr)) {
		return Error_VirtualAllocEx;
	}

	DWORD64 ntdll64 = GetModuleHandle64(L"ntdll.dll");
	DWORD64 ntdll_LdrLoadDll = GetProcAddress64(ntdll64, "LdrLoadDll");
	DWORD64 ntdll_RtlCreateUserThread = GetProcAddress64(ntdll64, "RtlCreateUserThread");
	DWORD64 ntdll_RtlExitThread = GetProcAddress64(ntdll64, "RtlExitUserThread");
	if (NULL == ntdll_LdrLoadDll || NULL == ntdll_RtlCreateUserThread || NULL == ntdll_RtlExitThread) {
		return Error_GetProcAddress;
	}


	// Fill stubs
	*(ULONGLONG*)((PUCHAR)Code + 12) = paramemter_mem_addr + 8;//第二个参数放到是paramemter_mem_addr+0x10
	*(ULONGLONG*)((PUCHAR)Code + 22) = paramemter_mem_addr;//第一个参数放到是句柄
	*(ULONGLONG*)((PUCHAR)Code + 32) = ntdll_LdrLoadDll;
	*(ULONGLONG*)((PUCHAR)Code + 48) = ret_32;

	*(ULONG*)((PUCHAR)code32To64+1) = shell_code_addr;


	file_path_mem_length *= 2;//最大为多大
	DWORD tmpSize = file_path_mem_length - 2;//当前字符串的大小
	DWORD64 address = paramemter_mem_addr + 0x18;
	if (!WriteProcessMemory64(handle, paramemter_mem_addr + 8, &tmpSize, 2, NULL) ||
		!WriteProcessMemory64(handle, paramemter_mem_addr + 10, &file_path_mem_length, 2, NULL) ||
		!WriteProcessMemory64(handle, paramemter_mem_addr + 0x10, &address, 8, NULL) ||//记录的字符串的地址,这里不是以12开始是因为8字节对齐,
		!WriteProcessMemory64(handle, paramemter_mem_addr + 0x18, (LPVOID)file_path, (size_t)::_tcslen(file_path) * sizeof(TCHAR), NULL) ||
		!WriteProcessMemory64(handle, shell_code_addr, Code, sizeof(Code), NULL)||
		!WriteProcessMemory64(handle, shell_code_32, code32To64, sizeof(code32To64), NULL)||
		!WriteProcessMemory64(handle, ret_32, RetFar, sizeof(RetFar), NULL)
		) {
		return Error_WriteProcessMemory;
	}
	DWORD64 hRemoteThread = 0;
	struct {
		DWORD64 UniqueProcess;
		DWORD64 UniqueThread;
	} client_id;
	DWORD64 a = X64Call(ntdll_RtlCreateUserThread, 10,
		(DWORD64)handle,					// ProcessHandle
		(DWORD64)NULL,                      // SecurityDescriptor
		(DWORD64)FALSE,                     // CreateSuspended
		(DWORD64)0,                         // StackZeroBits
		(DWORD64)NULL,                      // StackReserved
		(DWORD64)NULL,                      // StackCommit
		shell_code_32,					// StartAddress,如果是注入64位进程把这里改为shell_code_addr就行
		(DWORD64)NULL,                      // StartParameter
		(DWORD64)&hRemoteThread,            // ThreadHandle
		(DWORD64)&client_id);               // ClientID)//
	if (INVALID_HANDLE_VALUE == (HANDLE)hRemoteThread) {
		return Error_CreateRemoteThread;
	}
	return OK;
}


 

 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
没有任何实质性内容更新,仅内部架构调整,更易于派生模块使用; 首发于精易的 易语言全功能 SQLite3 数据库接口模块必须更新到本次版本后方可正常使用!下载:https://bbs.125.la/forum.php?mod=viewthread&tid=14361253 wow64 是在 64 位操作系统上允许 32 位程序(比如易编译的程序)执行的模拟器子系统;在 64 位操作系统中,不管你的程序是 32 还是 64 位的,其实都存在两个地址空间,正常情况下 32 位程序访问的自然是 32 位的地址空间,而 64 位程序访问其 64 位地址空间。 但是这两个空间是同时存在且可以切换的,本模块就是通过该原理切换到 64 位地址空间获取 ntdll.dll 相关函数进行调用(注:此基址是 64 位的,与平常获取的 32 位模块基址截然不同); 也就是:wow 环境 -> 进入 x64 环境 -> x64 函数调用 或 x64 汇编代码 -> 退出 x64 环境 -> wow 环境,以上必须在一个子程序内完成; 部分实现代码借鉴 c++ 开源代码:wow64ext,在此感谢作者 rewolf。 实现易语言纯 64 位汇编置入代码; 允许调用易程序 64 位 ntdll.dll 的所有函数,也就是你虽然开发的是 32 位程序,但可以实现很多 64 位函数所能实现的功能; 直接使用 64 位函数自由读写(注入) 64 位进程,与很多模块调用 NtWow64xxx 系列函数实现的方式有本质不同; 部分常用 ntdll.dll 函数已在模块直接提供,或以模拟 kernel32 函数的调用形式提供,v1.1 新增多个函数; 未提供函数获取地址后,可使用 X64Call 这个通用函数调用即可; 大部分提供的 64 位功能也同时提供了 32 位版本,以便兼容不同需求(模块在 32 位系统中不会开启 64 位功能引起异常,但 32 位功能依然可用); 支持加载任意 32/64 位 DLL,从此易语言可以调用外部 64 位 DLL 了(包括加载 kernel32.dll),v1.1 新增功能; 除了动态加载外,还支持 32 位 DLL 的内存加载,但 64 位只能加载本地 DLL 文件,v1.1 新增功能; 如有 BUG,请提供错误重现代码及执行环境,如非不可抗因素我都会及时更新的; 以下只是适用于 64 位的部分函数,模块中以相同命令形式实现的 32 位命令,这里就不列举了; 辅Zhu函数 fn_WOW64Enabled 如果你在代码中需要使用 64 位汇编或者操作 64 位进程,则初始化时应确保本函数返回真。实际只要是 64 位操作系统,均应返回 真 fn_ProcessIsX64 检测指定进程是否为 64 位进程 fn_CalcModOrFuncHash 使用过动态调用DLL的都清楚取模块基址和函数指针,微软默认使用字符串对比,本模块可使用哈希对比效率和易用上相对提升,本函数用于计算模块或函数哈希 X64Call 调用 64 位函数通用版本 X64CallArr 调用 64 位函数通用版本,数组方式传参,支持无限个数参数;【v1.2新增】 X64MemCopy 同类还有 X64MemCmp 函数;从 64 地址复制数据或 64 位地址与 32 位地址数据对比,但仅限进程内部 X64GetLong64 获取 64 位地址数值,同类函数还有:X64GetLong32、X64GetWord、X64GetByte X64GetTEB 取当前易程序 64 位 TEB,通过 TEB 再取 PEB,则进程和线程信息以及模块等一览无余了 GetNtdll64 ntdll.dll 在 64 位环境下的内存基址 GetModuleHandleEx64 通过模块哈希值获取其 64 位地址空间的内存基址(易进程而不是外部进程哦);同类还有 GetModuleHandle64 GetProcAddressEx64 通过函数哈希值或函数索引序号获取其 64 位调用地址;同类还有 GetProcAddress64 NtQuerySystemInformation64 cha询系统信息,可获取很多类别信息。这个 API 微软已不推荐使用并给出部分替代 API,但其个别功能十分好用且没用可替代品。cha询系统进程也是最全面的 OpenProcess64 打开进程句柄,关闭进程句柄时使用 CloseHandle64;【v1.1新增】 HeapAlloc64 堆管理函数,同类还有 GetDefaultHeap64/HeapReAlloc64/HeapFree64/HeapSize64;【v1.1新增】 malloc64 简化版默认堆管理函数,同类还有 realloc64/fre
模块原理: wow64 是在 64 位操作系统上允许 32 位程序(比如易编译的程序)执行的模拟器子系统;在 64 位操作系统中,不管你的程序是 32 还是 64 位的,其实都存在两个地址空间,正常情况下 32 位程序访问的自然是 32 位的地址空间,而 64 位程序访问其 64 位地址空间。 但是这两个空间是同时存在且可以切换的,本模块就是通过该原理切换到 64 位地址空间获取 ntdll.dll 相关函数进行调用(注:此基址是 64 位的,与平常获取的 32 位模块基址截然不同); 也就是:wow 环境 -> 进入 x64 环境 -> x64 函数调用 或 x64 汇编代码 -> 退出 x64 环境 -> wow 环境,以上必须在一个子程序内完成; 部分实现代码借鉴 c++ 开源代码:wow64ext,在此感谢作者 rewolf。 模块功能: 实现易语言纯 64 位汇编置入代码; 允许调用易程序 64 位 ntdll.dll 的所有函数,也就是你虽然开发的是 32 位程序,但可以实现很多 64 位函数所能实现的功能; 直接使用 64 位函数ziyou读写(注入) 64 位进程,与很多模块调用 NtWow64xxx 系列函数实现的方式有本质不同; 部分常用 ntdll.dll 函数已在模块直接提供,或以模拟 kernel32 函数的调用形式提供,v1.1 新增多个函数; 未提供函数获取地址后,可使用 X64Call 这个通用函数调用即可; 大部分提供的 64 位功能也同时提供了 32 位版本,以便兼容不同需求(模块在 32 位系统中不会开启 64 位功能引起异常,但 32 位功能依然可用); 支持加载任意 32/64 位 DLL,从此易语言可以调用外部 64 位 DLL 了(包括加载 kernel32.dll),v1.1 新增功能; 除了动态加载外,还支持 32 位 DLL 的内存加载,但 64 位只能加载本地 DLL 文件,v1.1 新增功能; 如有 BUG,请提供错误重现代码及执行环境,如非不可抗因素我都会及时更新的; 部分命令简述: 以下只是适用于 64 位的部分函数,模块中以相同命令形式实现的 32 位命令,这里就不列举了; 辅助函数 fn_WOW64Enabled 如果你在代码中需要使用 64 位汇编或者操作 64 位进程,则初始化时应确保本函数返回真。实际只要是 64 位操作系统,均应返回 真 fn_ProcessIsX64 检测指定进程是否为 64 位进程 fn_CalcModOrFuncHash 使用过动态调用DLL的都清楚取模块基址和函数指针,微软默认使用字符串对比,本模块可使用哈希对比效率和易用上相对提升,本函数用于计算模块或函数哈希 易内部命令 X64Call 调用 64 位函数通用版本 X64MemCopy 同类还有 X64MemCmp 函数;从 64 地址复制数据或 64 位地址与 32 位地址数据对比,但仅限进程内部 X64GetLong64 获取 64 位地址数值,同类函数还有:X64GetLong32、X64GetWord、X64GetByte X64GetTEB 取当前易程序 64 位 TEB,通过 TEB 再取 PEB,则进程和线程信息以及模块等一览无余了 GetNtdll64 ntdll.dll 在 64 位环境下的内存基址 GetModuleHandleEx64 通过模块哈希值获取其 64 位地址空间的内存基址(易进程而不是外部进程哦);同类还有 GetModuleHandle64 GetProcAddressEx64 通过函数哈希值或函数索引序号获取其 64 位调用地址;同类还有 GetProcAddress64 NtQuerySystemInformation64 查询系统信息,可获取很多类别信息。这个 API 微软已不推荐使用并给出部分替代 API,但其个别功能十分好用且没用可替代品。查询系统进程也是最全面的 OpenProcess64 打开进程句柄,关闭进程句柄时使用 CloseHandle64;【v1.1新增】 HeapAlloc64 堆管理函数,同类还有 GetDefaultHeap64/HeapReAlloc64/HeapFree64/HeapSize64;【v1.1新增】 malloc64 简化版默认堆管理函数,同类还有 realloc64/free64 RtlUnicodeToAnsi64 内核实现的 Unicode、Ansi 结构(不是数据指针)管理函数,同类还有:RtlInitAnsiString64/RtlFreeAnsiString64、RtlInitUnicodeString64/RtlFreeUnicodeString64、RtlAnsiToUnicode
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值