C++逆向
目录
一. 人物基址及相关属性偏移
- CE搜索数值,如血量
- OD追基址
- 龙龙遍历其它偏移
二. 查找人物状态基址及偏移
- CE搜索人物状态
- OD追基址
三. 人物怪物二叉树
- CE搜索NPC名字
- OD追基址,追到递归,放弃重来
- CE搜索怪物血量
- OD追基址,追到二叉树,追出树根
- 根据二叉树特性,在汇编中可推测出关键标志位,怪物ID及怪物对象
- 在怪物对象下可找到怪物属性(参考人物偏移)
四. DLL显示窗口
-
创建MFC_DLL(
- 创建项目 => MFC动态链接库
-
在创建DLL内添加窗口
- 资源视图 => rc文件右击 => 添加资源 => Dialog
-
添加窗口控件类
- dialog窗口右击 => 添加类(如CMainDialog)
-
线程创建并显示窗口
- 创建多线程
- 创建窗口对象,用new来初始化,用DoModal显示出来
- 释放new的内存空间
- 释放dll空间并退出dll
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
//唯一的 CMainDllApp 对象 CMainDllApp theApp; CMainDialog *PMainDialog; DWORD WINAPI _显示窗口(LPARAM lParam) { PMainDialog = new CMainDialog; //用new的方式分配内存空间 PMainDialog->DoModal(); //以模态化显示 delete PMainDialog; //释放new分配的内存空间 FreeLibraryAndExitThread(theApp.m_HInstance,1); //释放dll空间并退出dll return TRUE; } //CMainDllApp 初始化 BOOL CMainDllApp::InitInstance() { CWinApp::InitInstance(); ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)_显示窗口,NULL,0,NULL); return TRUE; }
五. 编写注入器
-
新建MFC应用
-
提升扠限
-
获取进程钥匙: OpenProcessToken()
-
获取当前进程句柄: GetCurrentProcess()
-
查看权限: LookupPrivilegeValue(
-
设置新权限: AdjustTokenPrivileges()
-
关闭进程句柄: CloseHandle()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
void _提权() { //1. 获取进程钥匙 HANDLE 进程_钥匙; if(FALSE == OpenProcessToken(GetCurrentProcess(),//进程句柄=>当前进程 TOKEN_ALL_ACCESS, //所有权限 &进程_钥匙)); //存放钥匙 { MessaseBox(NULL,_T("打开进程访问令牌失败!"),_T("错误提示"),MB_OK); return; } //2.查看进程里面的特权信息 LUID 进程_权限; if(FALSE == LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&进程_权限)) { MessaseBox(NULL,_T("查看进程权限信息失败!"),_T("错误提示"),MB_OK); return; } //3. 调节进程权限 TOKEN_PRIVILEGES 进程_新特权; 进程_新特权.PrivilegCount = 1; //特权个数 进程_新特权.Privileg[0].Attributes = SE_PRIVILEGE_ENABLED; //启用特权 进程_新特权.Privileg[0].Luid = 进程_权限; //将查到的luid存放到luid里面 if(FALSE == AdjustTokenPrivileges(进程_钥匙,FALSE,&进程_新特权,sizeof(进程_新特权),NULL,NULL)) { MessaseBox(NULL,_T("打开进程权限失败!"),_T("错误提示"),MB_OK); return; } //4. 关闭进程句柄 CloseHandle(进程_钥匙); }
-
-
开始注入
- 获取窗口句柄: FindWindow()
- 根据窗口句柄获取进程ID PID: GetWindowThreadProcessId()
- 根据PID获取进程句柄: OpenProcess()
- 在远程进程中申请内存空间: VirtualAllocEx()
- 在远程进程中写入咱们的DLL地址: WriteProcessMemory()
- 获取LoadLibraryA()函数地址: GetProcAddress()
- 在远程进程中创建一个线程: CreateRemoteThread()
- 清理战场
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
void _注入辅助() { //1. 查找窗口 HWND 游戏窗口句柄; 游戏窗口句柄 = FindWindow(游戏窗口类名,NULL); if(游戏窗口句柄 == NULL) { MessaseBox(NULL,_T("游戏未启动"),_T("错误提示"),MB_OK); return; } //2. 获取进程ID PID DWORD 进程_PID = 0; GetWindowThreadProcessId(游戏窗口句柄,&进程_PID); if(进程_PID == 0) { MessaseBox(NULL,_T("获取进程PID失败"),_T("错误提示"),MB_OK); return; } //进程: 一个进程中的程序 //一个进程可以有多个窗口 //3. 获取进程句柄 HANDLE 进程_进程句柄 = NULL; 进程_进程句柄 = OpenProcess(PROCESS_ALL_ACCESS,FALSE,进程_PID); if(进程_进程句柄 == NULL) { MessaseBox(NULL,_T("获取进程PID失败"),_T("错误提示"),MB_OK); return; } //4. 在远程进程中申请内存空间 LPVOID 申请空间地址 = NULL; DWORD 申请空间 =256; 申请空间地址 = VirtualAllocEx(进程_进程句柄,NULL,申请空间,MEM_COMMIT,PAGE_READWRITE); if(申请空间地址 == NULL) { MessaseBox(NULL,_T("获取进程PID失败"),_T("错误提示"),MB_OK); return; } //5. 将DLL的路径写入到远程进程中 /* CHAR 当前路径[256]; CHAR DLL路径[256]; GetCurrentDirectoryA(sizeof(当前路径),当前路径); //获取运行目录 strcpy_s(DLL路径,当前路径); strcpy_s(DLL路径,"\\"); strcpy_s(DLL路径,DLL名); */ SIZE_T 实际写入大小 = 0; CHAR DLL路径[256] = "C:\\Users\\Admin\\Desktop\\MyDll.dll " if(FALSE == WriteProcessMemory(进程_进程句柄,申请空间地址,DLL路径,strlen(DLL路径)+1,&实际写入大小)) { MessaseBox(NULL,_T("DLL写入失败"),_T("错误提示"),MB_OK); return; } LPTHREAD_START_ROUTINE 函数地址 = NULL; 函数地址 = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA"); //6. 在远程进程中创建一个线程 HANDLE 进程_远程线程句柄 = NULL; 进程_远程线程句柄 = CreateRemoteThread(进程_进程句柄,NULL,0,函数地址,申请空间地址,0,NULL); if(进程_远程线程句柄 == NULL) { MessaseBox(NULL,_T("创建远程线程失败"),_T("错误提示"),MB_OK); return; } WaitForSingleObject(进程_远程线程句柄,0xFFFFFFFF); CloseHandle(进程_远程线程句柄); VirtualFreeEx(进程_进程句柄,申请空间地址,申请空间,MEM_DECOMMIT); CloseHandle(进程_进程句柄); }
六. 实现读取游戏数据
- 实现读取人物信息
- 用指针的方式读取内存
|
|