当前位置: 首页 > news >正文

做理财的网站有哪些内容本溪网站建设

做理财的网站有哪些内容,本溪网站建设,简单html网站模板,函数自定义wordpress编译与链接 环境配置 masm32 masm32 是微软的 masm32 的民间工具集合。该工具集合除了 asm32 本身的汇编器 ml 外还提供了#xff1a; SDK 对应的函数声明头文件和 lib 库。32 位版本的 link#xff08;原版本是 16 位#xff0c;这里的 32 位版本的 link 来自 VC 6.0 SDK 对应的函数声明头文件和 lib 库。32 位版本的 link原版本是 16 位这里的 32 位版本的 link 来自 VC 6.0用于编译资源的 rc同样来自 VC 6.0 环境配置 安装 masm32 。将 masm32 下的 bin 目录添加到 path 。环境变量新建 include 将 masm32 目录下的 include 目录添加进去。环境变量新建 lib 将 masm32 目录下的 lib 目录添加进去。 编译链接 ml /c /coff %1.asm link /subsystem:windows %1.obj编译脚本 echo off set path%path%;C:\masm32\bin set include%include%;C:\masm32\include set lib%lib%;C:\masm32\lib echo onml /c /coff test.asm link /subsystem:windows test.obj测试程序 .386 .model flat, stdcall option casemap:NONE include windows.inc include user32.inc includelib user32.lib.datag_szTitle db hello,world!,0.code ENTRY:invoke MessageBoxA, NULL, offset g_szTitle, NULL, MB_OK end ENTRYendsRadASM RadASM 是一款 ASM 的编辑器。相比与 VSCode RadASM 支持结构体成员和 API 的代码提示。这里推荐下载 RadASM2.2.1.2汉化增强版该版本集成了调试器、编译器等环境。 常见设置位置及注意事项 修改调试器路径工程 → 工程选项 → 调试运行修改编辑器主题选项 → 颜色及关键字 → 选择主题并点击载入虽然 RadASM 可以设计对话框但不会自动生成对应的头文件需要手动定义相关的消息编号。以 printf 函数为例使用 C 运行库时如果用的是 msvcrt.lib 则函数名为 crt_printf 属于动态链接。 16 位与 32 位汇编区别 源文件格式 文件三件套.386 .model flat, stdcall option casemap:NONE.386汇编使用的指令集同样也可以选择 .386P.486 等等。这里默认选 .386 。flat指定汇编程序所使用的内存模型。32 位只能选 flat因为 32 位程序可以访问 4GB 内存空间不需要分段。stdcall指定函数默认调用约定为 stdcall 。option其它选项和 ml 或 link 的命令行选项等价。32 位汇编一般只用 casemap 。 casemap对应的 ml 选项英文解释ALL/CuMap all identifiers to upper case所有标识符转大写大小写不敏感NONE/CpReverse case of user identifies所有标识符维持原有大小写大小写敏感NOTPULIC/CxPreserve case in publics,externs 分段 32 位汇编取消了分段改用内存属性来划分称作节section、内存区或内存块。 节可读可写可执行备注.DATA√√初始化的全局变量.CONST√只读数据区.DATA?√√未初始化的全局变量.CODE√√代码 调试 32 位汇编调试一般使用 OD 或者 x64dbg 。 操作或者快捷键位置说明选项 → 添加到右键资源管理器可以在 exe 右键使用 od 打开F7单步步入F8单步步过F9运行Ctrl F2重新打开F2 或双击机器码设置断点空格或双击反汇编汇编选中 空格内存修改内存Ctrl G内存反汇编堆栈转到指定地址*堆栈转到栈顶 寄存器 长度 寄存器扩展到了 32 位命名为 Exx低 16 位对应原来的 8086 的寄存器名称。 寄存器组 32 位中3 环可用寄存器。 16 位32 位通用寄存器EAXECXEBXEDXESIEDIEBPESP√√标志寄存器EFLAGS√√指令指针寄存器EIP√√段寄存器CSDSESSS√ 指令 8086 所有指令在 32 位保持原有功能不变操作数长度扩充到 32 位。 寻址 相较于 16 位汇编32 位汇编的寻址变得宽松了除了原有的寻址方式之外额外增加了比例因子寻址。 EA { 无 EAX EBX ECX EDX ESI EDI EBP ESP } 基址寄存器 { 无 EAX EBX ECX EDX ESI EDI EBP } 变址寄存器 × { 1 2 4 8 } 比例因子 { 无 8 位 16 位 } 偏移常量 \text{EA}\underset{\text{基址寄存器}}{{\color{Green} \begin{Bmatrix} \text{无}\\ \text{EAX}\\ \text{EBX}\\ \text{ECX}\\ \text{EDX}\\ \text{ESI}\\ \text{EDI}\\ \text{EBP}\\ \text{ESP} \end{Bmatrix}}} \underset{\text{变址寄存器}}{{\color{Blue} \begin{Bmatrix} \text{无}\\ \text{EAX}\\ \text{EBX}\\ \text{ECX}\\ \text{EDX}\\ \text{ESI}\\ \text{EDI}\\ \text{EBP} \end{Bmatrix}}} \times \underset{\text{比例因子}}{{\color{Blue} \begin{Bmatrix} {\color{Purple} 1} \\ {\color{Purple} 2} \\ {\color{Purple} 4} \\ {\color{Purple} 8} \end{Bmatrix}}} \underset{\text{偏移常量}}{{\color{Tan} \begin{Bmatrix} \text{无} \\ \text{8 位}\\ \text{16 位} \end{Bmatrix}} } EA基址寄存器⎩ ⎨ ⎧​无EAXEBXECXEDXESIEDIEBPESP​⎭ ⎬ ⎫​​变址寄存器⎩ ⎨ ⎧​无EAXEBXECXEDXESIEDIEBP​⎭ ⎬ ⎫​​×比例因子⎩ ⎨ ⎧​1248​⎭ ⎬ ⎫​​偏移常量⎩ ⎨ ⎧​无8 位16 位​⎭ ⎬ ⎫​​ 新增指令 16 位32 位说明CBWCWDCBWCWDCWDECDQ符号扩充LODSBLODSWLODSBLODSWLODSD串读取STOSBSTOSWSTOSBSTOSWSTOSD串存储MOVSBMOVSWMOVSBMOVSWMOVSD串读取MOVSX reg, regMOVSW reg, mem符号扩展MOVZX reg, regMOVZW reg, mem无符号扩展移位指令 cl/1移位指令 cl/1移位指令 reg, imm8移位指令 mem, imm8RCLRCRROLRORSAL/SHLSARSHR 汇编版第一个窗口 .386 .model flat, stdcall option casemap:NONEinclude windows.inc include user32.inc include gdi32.inc include kernel32.incincludelib user32.lib includelib gdi32.lib includelib kernel32.lib.datag_szClassName db MyWindowClass, 0g_szTitle db My first asm32 window, 0g_szTip db Failed to create window, 0.code ; 过程函数 MainWndProc proc hWnd:HWND, nMsg:UINT, wParam:WPARAM, lParam:LPARAM.IF nMsg WM_DESTROYinvoke PostQuitMessage, 0.ENDIFinvoke DefWindowProc, hWnd, nMsg, wParam, lParamret MainWndProc endpWinMain proc hInstance:HINSTANCElocal wc: WNDCLASSlocal hWnd:HWNDlocal msg:MSG; 注册窗口类mov wc.style, CS_HREDRAW or CS_VREDRAWmov wc.lpfnWndProc, offset MainWndProcmov wc.cbClsExtra, 0mov wc.cbWndExtra, 0mov eax, hInstancemov wc.hInstance, eaxinvoke LoadIcon, NULL, IDI_APPLICATIONmov wc.hIcon, eaxinvoke LoadCursor, NULL, IDC_ARROWmov wc.hCursor, eaxinvoke GetStockObject, WHITE_BRUSHmov wc.hbrBackground, eaxmov wc.lpszMenuName, NULLmov wc.lpszClassName, offset g_szClassNameinvoke RegisterClass, addr wc; 创建窗口invoke CreateWindowEx, NULL, offset g_szClassName, offset g_szTitle, WS_OVERLAPPEDWINDOW, \CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, \NULL, NULL, hInstance, NULLmov hWnd, eax.if eax NULLinvoke MessageBox, NULL, offset g_szTip, offset g_szTitle, MB_OKret.endif; 显示窗口invoke ShowWindow, hWnd, SW_SHOW; 更新窗口invoke UpdateWindow, hWnd; 消息循环.WHILE TRUEinvoke GetMessage, addr msg, NULL, 0, 0.IF eax 0.break.ENDIFinvoke TranslateMessage, addr msginvoke DispatchMessage, addr msg.ENDWret WinMain endpENTRY:invoke GetModuleHandle, NULLinvoke WinMain, eaxinvoke ExitProcess, 0 end ENTRYends在调试程序的时候 OD 可以自动查找到窗口的过程函数。 资源的使用 这里以对话框为例介绍汇编如何使用资源。 首先在 VisualStuduo 中创建项目并且在项目中创建一个对话框资源。 编写汇编程序使用对话框资源。 .386 .model flat, stdcall option casemap:NONE include windows.inc include user32.inc include gdi32.inc include kernel32.incincludelib user32.lib includelib gdi32.lib includelib kernel32.libIDD_DIALOG1 equ 101.datag_szClassName db MyWindowClass, 0g_szTitle db My first asm32 window, 0g_szTip db Failed to create window, 0 .codeDlgProc proc hWnd:HWND, nMsg:UINT, wParam:WPARAM, lParam:LPARAM.IF nMsg WM_CLOSEinvoke EndDialog, hWnd, 0.ENDIFmov eax, FALSEret DlgProc endpWinMain proc hInstance:HINSTANCEinvoke DialogBoxParam, hInstance, IDD_DIALOG1, NULL, offset DlgProc, 0ret WinMain endpENTRY:invoke GetModuleHandle, NULLinvoke WinMain, eaxinvoke ExitProcess, 0 end ENTRYends编译的时候注意要添加相关库的路径到环境变量中其中链接的时候需要将资源链接到最终的可执行文件中。 echo off set path%path%;C:\masm32\bin set include%include%;C:\masm32\include;C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\um\;C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\shared set lib%lib%;C:\masm32\lib echo onrc RC.rc ml /c /coff test.asm link /subsystem:windows /OUT:test.exe RC.RES test.obj 联合编译 与 dll 不同obj 编译是直接链接到目标程序中的。 汇编调用 C 汇编只能在链接阶段实现对 C 函数的调用。 在 VC6.0新版 VS 貌似不太兼容的项目中新建一个源文件并编写 MyAdd 函数 extern C int MyAdd(int nVal1, int nVal2) {return nVal1 nVal2; }这里要注意 需要加 extern C 避免 C 名称修饰。不能使用与汇编指令冲突的函数名称。这里没有声明函数类型因此默认为 C 调用约定。 然后选中该文件右键选择 Compile 将其编译成 obj 文件。这里可能会报 C1010 错误这是因为找不到项目设置的预编译文件头需要在 Project → Settings 中设置不使用预编译头。 奖编译好的 Add.obj 复制到 RadASM 项目目录下并在 RadASM 的 项目 → 工程选项 → 连(链)接 中添加 Add.obj 。 之后汇编程序中声明 MyAdd 函数后就可以直接调用。 .586 .model flat,stdcall option casemap:noneMyAdd proto C:DWORD, :DWORD.code start:invoke MyAdd, 4, 5invoke ExitProcess, 0 end startC 调用汇编 创建 Sub.asm 文件编写如下汇编代码编译生成 Sub.obj 。因为这里只需要 MySub 函数因此不需要指定程序入口。 .586 .model flat,stdcall option casemap:none.code MySub proc nVal1:DWORD, nVal2:DWORDmov eax, nVal1sub eax, nVal2retMySub endpend 这里想要编译新添加的 asm 文件需要在 项目 → 工程选项 → 编译 中添加文件名不过我这里貌似不行可能 cmd 版本问题。可以把 RadASM 的编译命令复制出来手动修改。 将编译生成的 Sub.obj 放到 VC 项目目录下在项目设置中添加该 obj 文件。 这时候就可以在 C 语言中调用汇编函数了。 extern C int __stdcall MySub(int,int);int main() {MySub(2,3);return 0; }DLL 调用 联合编译可能会因版本问题识别因此汇编与 C 之间的调用最好通过 DLL 实现。 汇编调用 C 首先创建一个 DLL 项目本质是在生成 exe 的链接命令中添加一个 /DLL 参数来生成 dll另外需要用 /DEF 参数指明 def 文件来指明要导出哪些函数编写并导出函数。 #include pch.hextern C __declspec(dllexport) void Msg(char* szMsg) {MessageBoxA(NULL, szMsg, NULL, MB_OK); }BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) {switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE; }将 DLL 项目编译产生的 dll 和 lib 文件复制到汇编工程目录下然后 includelib 掉入库并声明函数即可调用。 .586 .model flat,stdcall option casemap:noneincludelib Msg.lib Msg proto C :DWORD.datag_szHello db Hello,World!,0.code start:invoke Msg, offset g_szHello end startC 调用汇编 新建 DLL 类型的汇编项目项目代码如下 .586 .model flat,stdcall option casemap:noneinclude windows.inc include user32.inc include gdi32.inc include kernel32.incincludelib user32.lib includelib gdi32.lib includelib kernel32.lib.codeAsmMsg proc C szMsg:LPSTRinvoke MessageBox,NULL, szMsg, NULL, MB_OKretAsmMsg endpDllMain proc hinstDll:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOIDmov eax, TRUEretDllMain endpend DllMain在汇编中如果想要导出 AsmMsg 函数需要在项目中的 .def 文件中添加该函数 EXPORTSAsmMsg编译后将生成的 .dll 文件复制到 C/C 项目中可执行文件生成的目录.lib 文件复制到项目中源文件所在的目录。在源文件中导入 lib 文件并声明函数即可使用。这可能会编译失败可能是因为高版本的 SafeSEH 机制与导入的 dll 冲突导致的关闭 SafeSEH 即可。 #pragma comment(lib, AsmDll.lib) extern C void AsmMsg(const char *);int main() {AsmMsg(Hello,World!);return 0; }内联汇编相关 内联汇编 内联汇编即在 C/C 中使用的汇编在 VC 中需要用 __asm 关键字指明。如果需要写多条汇编语句可以用 {} 表示汇编范围然后汇编语句按行进行分隔。另外在内联汇编中同时支持汇编和 C/C 注释 int main() {// 一条汇编语句__asm mov eax, eax// 多条汇编语句__asm {/* 这是注释 */mov ebx, ebx; 这是注释mov ecx, ecx// 这是注释}return 0; }在内联汇编中可以直接使用 C/C 中定义的变量。需要注意例如下面代码中汇编里面的 nAry[2*4] 和 C 代码中的 nAry[2] 指的是同一个地址。 #includestdio.hint main() {int nAry[10]{};__asm {mov eax, 0x114514;mov nAry[2 * 4], eax}printf(%x\n, nAry[2]);return 0; }在内联汇编中原本 masm 的宏不能使用但是属性还是可以使用的例如下面的代码。 int main() {int nAry[10]{};__asm {mov eax, size nArymov eax, type nArymov eax, length nAry}return 0; }裸函数 裸函数通常与内联汇编配合使用该种函数通过 _declspec(naked) 来声明函数中无任何预留汇编代码。 #include stdio.h_declspec(naked) void func() {__asm {push ebpmov ebp, espsub esp, __LOCAL_SIZE}int n;scanf_s(%d, n);__asm {leaveretn} }int main() {func();return 0; }关于裸函数有如下注意事项 裸函数中的局部变量的声明不能有初始值。裸函数中的局部变量会默认存储在 [ebp - xxx] 位置因此需要手动抬栈为局部变量预留栈空间避免裸函数内部函数调用破坏局部变量。可以使用内置宏 __LOCAL_SIZE 让编译器自动计算需要开辟的栈空间。 补丁 补丁即在二进制程序中通过 patch 的方式添加功能的技术。 这里我们以在扫雷程序中添加退出提示弹框为例讲解 Win32 程序的调试分析和打补丁的过程。 寻找窗口过程处理函数 Win32 程序的核心逻辑大多在窗口过程处理函数或者通过该函数调用的函数中因此我们首先要做的就是寻找窗口过程处理函数。 这里提供提供两个寻找窗口过程处理函数的思路。 第一种思路在过创建窗口的函数下断点然后根据参数来确定窗口过程处理函数。首先在在 Executable modules 窗口中选择模块然后 Ctrl n 查看模块的导入导出表然后在 RegisterClassW 和 DialogBoxParam 等关键函数下断点。下断点的方式可以是右键函数选择查看参考找到所有调用函数的位置然后手动下断点也可以右键选择在每个参考上设置断点。之后继续运行程序结果程序在 RegisterClassW 函数断下来 通过分析参数可知窗口的过程函数地址为 0x1001BC9 可以在内存窗口中选择地址数据然后右键选择反汇编窗口跟随 DWORD 跳转到过程函数。 另一种方法是 F9 运行程序然后再 Windows 窗口右键选择刷新即可看到程序注册的所有窗口。 右键对应的 ClsProc 选择跟随 ClsProc 即可跳转到对应的窗口过程处理函数。 寻址关闭窗口消息的处理代码 过程窗口虽然找到了但是过程窗口处理大量的消息如果在过程窗口下断点很难调试到关闭消息。 我们首先知道过程 WM_CLOSE 消息对应的值为 0x10 且为窗口过程函数的第二个参数。因此我们可以通过 IDA 找到 0x10 对应的代码即可。 另一种方法是下条件断点。在过程处理函数处 Shift F2 添加条件断点条件为 dword ptr [esp 8] 0x10 即第二个参数为 0x10 。如果断点处变为粉色说明条件断点添加成功。 之后 F9 继续运行程序然后点击窗口关闭按钮可以成功断下。 最终的结果是对于 WM_CLOSE 消息程序在 0x1001C16 地址处直接跳转到 0x010021A9 调用 DefWindowProcW 函数处理消息。 patch 程序添加功能 由于扫雷程序没有开启 DEP 保护因此程序加载到内存的所有段都具有可执行权限。 这里选择在 0x01001C16 位置处修改代码跳转到 01004A60 地址处然后在该地址处实现确认对话框。 跳转的位置 01001C03 . 8BC2 mov eax,edx ... 01001C13 . 83E8 38 sub eax,0x38 01001C16 . E9 452E0000 jmp winmine.01004A60 01001C1B 90 nop跳转到的位置 01004A60 \83FA 10 cmp edx,0x10 ; Default case of switch 01001C05 01004A63 .^ 0F85 40D7FFFF jnz winmine1.010021A9 01004A69 . 6A 01 push 0x1 ; /Style MB_OKCANCEL|MB_APPLMODAL 01004A6B . 68 A04A0001 push winmine1.01004AA0 ; |Title sky123的补丁 01004A70 . 68 904A0001 push winmine1.01004A90 ; |Text 是否需退出 01004A75 . 6A 00 push 0x0 ; |hOwner NULL 01004A77 . FF15 B8100001 call dword ptr ds:[USER32.MessageBoxW; \MessageBoxW 01004A7D . 83F8 01 cmp eax,0x1 01004A80 .^ 0F84 23D7FFFF je winmine1.010021A9 01004A86 .^ E9 30D7FFFF jmp winmine1.010021BB跳回的位置 010021A9 FF75 14 push dword ptr ss:[ebp0x14] ; /lParam 0x0; Default case of switch 01001F5F 010021AC . |FF75 10 push dword ptr ss:[ebp0x10] ; |wParam 10 (16.) 010021AF . |FF75 0C push dword ptr ss:[ebp0xC] ; |Message MSG(0x17B193E) 010021B2 . |FF75 08 push dword ptr ss:[ebp0x8] ; |hWnd 01001BC9 010021B5 . |FF15 24110001 call dword ptr ds:[USER32.DefWindowProcW] ; \DefWindowProcW 010021BB |5F pop edi ; user32.76CF2BC3 010021BC . |5E pop esi ; user32.76CF2BC3 010021BD . |5B pop ebx ; user32.76CF2BC3 010021BE . |C9 leave 010021BF . |C2 1000 retn 0x10参考的 MessageBox 调用代码 010039CB |. 6A 10 push 0x10 ; /Style MB_OK|MB_ICONHAND|MB_APPLMODAL 010039CD |. 8D85 00FFFFFF lea eax,[local.64] ; | 010039D3 |. 50 push eax ; |Title FFFFFFC9 ??? 010039D4 |. 8D85 00FEFFFF lea eax,[local.128] ; | 010039DA |. 50 push eax ; |Text FFFFFFC9 ??? 010039DB |. 6A 00 push 0x0 ; |hOwner NULL 010039DD |. FF15 B8100001 call dword ptr ds:[USER32.MessageBoxW; \MessageBoxW call dword ptr ds:[0x10010B8]字符串位置 01004A90 2F 66 26 54 00 97 00 90 FA 51 1F FF 00 00 00 00 是否需退出.. 01004AA0 73 00 6B 00 79 00 31 00 32 00 33 00 84 76 65 88 sky123的补 01004AB0 01 4E 00 00 00 00 00 00 00 00 00 00 00 00 00 丁.......patch 时有以下几点需要注意 分析汇编可知 edx 寄存器存放的是消息号因此可以直接在补丁代码中用 edx 寄存器判断是否是 WM_CLOSE 消息。MessageBoxW 函数是通过导入表进行调用的这里可以参考程序中其他调用 MessageBoxW 函数的代码。根据 MessageBoxW 的返回值来判断用户点击的是确认还是取消按钮。#define IDOK 1 #define IDCANCEL 2如果用户点击的是取消按钮则跳转至 0x010021BB 由窗口处理函数完成平栈工作。MessageBoxW 需要 UNICODE 字符串OD 编辑 UNICODE 字符串的时候不能用输入法输入中文而是通过右键 UNICODE 框选择粘贴将提前复制好的字符串粘贴进去。 完成修改后随便选中一处修改然后 右键 → 复制到可执行文件 → 所有修改 → 全部复制 然后在弹出的窗口 右键 → 保存文件 即可将 patch 好的程序 dump 下来。 目前的 patch 程序虽然点击关闭按钮后弹出的对话框功能正常但是通过 Game → 退出(X) 退出时无论选择确定还是取消窗口都会消失。在 SDK 学习中我们知道点击菜单上的退出时发送的是 WM_COMMAND 消息因此我们在 OD 的 Windows 窗口右键窗口处理函数选择在 ClassProc 上设置消息断点来监控 WM_COMMAND 消息。 通过调试我们发现程序在处理该 WM_COMMAND 消息时执行的代码如下。程序会先调用 ShowWindow 将窗口隐藏起来然后进行后续操作。 01001E9F . 57 push edi ; /ShowState SW_HIDE 01001EA0 . FF35 245B0001 push dword ptr ds:[0x1005B24] ; |hWnd 007F075A (扫雷,class扫雷) 01001EA6 . FF15 34110001 call dword ptr ds:[USER32.ShowWindow] ; \ShowWindow 01001EAC 57 push edi ; /lParam 0x0 01001EAD . 68 60F00000 push 0xF060 ; |wParam 0xF060 01001EB2 . 68 12010000 push 0x112 ; |Message WM_SYSCOMMAND 01001EB7 . FF35 245B0001 push dword ptr ds:[0x1005B24] ; |hWnd 0x7F075A 01001EBD . FF15 00110001 call dword ptr ds:[USER32.SendMessageW; \SendMessageW 01001EC3 .^\E9 96FDFFFF jmp winmine2.01001C5E ... 01001C5E /33C0 xor eax,eax 01001C60 . |E9 56050000 jmp winmine2.010021BB ... 010021BB 5F pop edi 010021BC . |5E pop esi 010021BD . |5B pop ebx 010021BE . |C9 leave 010021BF . |C2 1000 retn 0x10我们将 ShowWindow 函数的调用代码 nop 掉后发现功能正常了。 重定位 向目标进程注入 shellcode 时由于位置不确定因此需要对代码进行重定位。重定位可以先通过 call pop 的方式获取 shellcode 地址然后修正地址即可。 下面的例子是向扫雷程序中注入一段弹窗代码并执行。 .386 .model flat, stdcall option casemap:NONEinclude windows.inc include user32.inc include gdi32.inc include kernel32.incincludelib user32.lib includelib gdi32.lib includelib kernel32.lib.datahInstance dd ?CommandLine LPSTR ?g_szWinMineCap db 扫雷,0g_szUser32 db user32.dll,0g_szMessageBox db MessageBoxA,0.code CODE_BEG:jmp MSG_CODEg_szText db 注入代码,0g_szCaption db 温情提示,0g_pfnMessageBox dd 0MSG_CODE:call NEXT NEXT:pop ebxsub ebx, offset NEXTpush MB_OKmov eax, offset g_szCaptionadd eax, ebxpush eaxmov eax, offset g_szTextadd eax, ebxpush eaxpush NULLmov eax, offset g_pfnMessageBoxadd eax, ebxcall dword ptr [eax]retCODE_END:g_dwCodeSize dd offset CODE_END - offset CODE_BEGWinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORDLOCAL hWindWinmine:HWNDLOCAL dwProcId:DWORDLOCAL hProc:HANDLELOCAL pBuff:LPVOIDLOCAL dwBytesWrited:DWORDLOCAL hUser32:HMODULELOCAL dwOldProc:DWORDinvoke VirtualProtect, offset g_pfnMessageBox, size g_pfnMessageBox, PAGE_EXECUTE_READWRITE, addr dwOldProcinvoke LoadLibrary, offset g_szUser32mov hUser32, eaxinvoke GetProcAddress, hUser32, offset g_szMessageBoxmov g_pfnMessageBox, eaxinvoke VirtualProtect, offset g_pfnMessageBox, size g_pfnMessageBox, dwOldProc, addr dwOldProcinvoke FindWindow, NULL, offset g_szWinMineCapmov hWindWinmine, eaxinvoke GetWindowThreadProcessId, hWindWinmine, addr dwProcIdinvoke OpenProcess, PROCESS_ALL_ACCESS, FALSE, dwProcIdmov hProc, eaxinvoke VirtualAllocEx, hProc, NULL, g_dwCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITEmov pBuff, eaxinvoke WriteProcessMemory, hProc, pBuff, offset CODE_BEG, g_dwCodeSize, addr dwBytesWritedinvoke CreateRemoteThread, hProc, NULL, 0, pBuff, NULL, NULL, NULLxor eax, eaxretWinMain endpstart:invoke GetModuleHandle,NULLmov hInstance, eaxinvoke GetCommandLinemov CommandLine, eaxinvoke WinMain,hInstance, NULL, CommandLine, SW_SHOWDEFAULTinvoke ExitProcess, 0end startshellcode 注入的其中一个作用就是调用游戏中某个特定的函数实现某些特定的功能。不过在这种情境下只是传参和调用函数不需要考虑重定位问题。要实现这个工具需要解决的是如何进行汇编。这里我使用的是 XEDParse 。 #include iostream #include XEDParse.h#pragma comment(lib, XEDParse_x86.lib)XEDPARSE xed{};void MyAsm(const char* ins) {printf_s(%s , ins);strcpy_s(xed.instr, ins);XEDParseAssemble(xed);for (int i 0; i (int)xed.dest_size; i) {printf_s(%02X%c, xed.dest[i], i xed.dest_size - 1 ? \n : );}xed.cip xed.dest_size; }int main() {xed.x64 false;xed.cip 0x01003e21;MyAsm(push 70);MyAsm(push 01001390);MyAsm(call 0100400C);return 0; } /* push 70 6A 70 push 01001390 68 90 13 00 01 call 0100400C E8 DF 01 00 00 */API Hook 基本原理 以 MessageBoxW 为例windows 的 API 往往都是以 mov edi, edi; push ebp; mov ebp, esp 开头的这是微软为 API Hook 准备的。因为这段汇编对应的机器码长度恰好是 5 字节与 jmp 指令的长度相等并且函数开头一定是某一条指令的开头不会出现 Hook 到某条指令中间的情况。 76D3A270 8BFF mov edi,edi ; winmine2.ModuleEntryPoint 76D3A272 /. 55 push ebp 76D3A273 |. 8BEC mov ebp,esp 76D3A275 |. 833D 94ACD676cmp dword ptr ds:[0x76D6AC94],0x0 76D3A27C |. 74 22 je short user32.76D3A2A0 76D3A27E |. 64:A1 1800000mov eax,dword ptr fs:[0x18] 76D3A284 |. BA 10B3D676 mov edx,user32.76D6B310 76D3A289 |. 8B48 24 mov ecx,dword ptr ds:[eax0x24] 76D3A28C |. 33C0 xor eax,eax 76D3A28E |. f0:0fb10a lock cmpxchg dword ptr ds:[edx],ecx 76D3A292 |. 85C0 test eax,eax 76D3A294 |. 75 0A jnz short user32.76D3A2A0 76D3A296 |. C705 30ADD676mov dword ptr ds:[0x76D6AD30],0x1 76D3A2A0 | 6A FF push -0x1 76D3A2A2 |. 6A 00 push 0x0 76D3A2A4 |. FF75 14 push [arg.4] 76D3A2A7 |. FF75 10 push [arg.3] 76D3A2AA |. FF75 0C push [arg.2] 76D3A2AD |. FF75 08 push [arg.1] 76D3A2B0 |. E8 0BFEFFFF call user32.MessageBoxTimeoutW 76D3A2B5 |. 5D pop ebp ; kernel32.76E87BA9 76D3A2B6 \. C2 1000 retn 0x10API Hook 的思路和前面打补丁类似只不过进行打补丁的是加载进去的 DLL 而不是负责代码注入的进程。 这里我们通过 API Hook 修改前面打过补丁的扫雷程序的弹框的标题。 .586 .model flat,stdcall option casemap:noneinclude windows.inc include user32.inc include gdi32.inc include kernel32.incincludelib user32.lib includelib gdi32.lib includelib kernel32.lib.datag_szUser32 db user32,0g_szMessageBoxW db MessageBoxW, 0g_szNewTitle db 41h, 00h, 50h, 00h, 49h, 00h, 20h, 00h, 48h, 00h, 6Fh, 00h, 6Fh, 00h, 6Bh, 00h, 20h, 00h, 4Bh, 6Dh, 0D5h, 8Bh, 00h, 00hg_pfnMessageBoxW dd 0 .codeHOOKCODE:mov edi, edipush ebpmov ebp, espmov [ebp 10h], offset g_szNewTitlemov eax, g_pfnMessageBoxWadd eax, 5 jmp eaxInstallHook proc uses ebxLOCAL hUser32:HMODULELOCAL dwOldProc:DWORD; 获取 MessageBox 地址invoke GetModuleHandle, offset g_szUser32mov hUser32, eaxinvoke GetProcAddress, hUser32, offset g_szMessageBoxWmov g_pfnMessageBoxW, eax; 计算跳转偏移mov eax, offset HOOKCODEsub eax, g_pfnMessageBoxWsub eax, 5push eaxinvoke VirtualProtect, g_pfnMessageBoxW, 1, PAGE_EXECUTE_READWRITE, addr dwOldProc; 修改跳转pop eaxmov ebx, g_pfnMessageBoxWmov byte ptr [ebx], 0e9h ; jmpmov dword ptr [ebx 1], eaxinvoke VirtualProtect, g_pfnMessageBoxW, 1, dwOldProc, addr dwOldProcretInstallHook endpDllMain proc hinstDll:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID.if fdwReason DLL_PROCESS_ATTACHinvoke InstallHook.endifmov eax, TRUEretDllMain endpend DllMain测试发现标题成功修改。 重入问题 如果想要在 Hook 代码中调用被 Hook 的函数会出现无限递归其中一种解决方法是在调用被 Hook 的函数前去除函数上的钩子调用完之后再将钩子重新加上。 .586 .model flat,stdcall option casemap:noneinclude windows.inc include user32.inc include gdi32.inc include kernel32.incincludelib user32.lib includelib gdi32.lib includelib kernel32.lib.datag_szUser32 db user32,0g_szMessageBoxW db MessageBoxW, 0g_szNewTitle db 41h, 00h, 50h, 00h, 49h, 00h, 20h, 00h, 48h, 00h, 6Fh, 00h, 6Fh, 00h, 6Bh, 00h, 20h, 00h, 4Bh, 6Dh, 0D5h, 8Bh, 00h, 00hg_pfnMessageBoxW dd 0 .codeInsertJmp proc uses ebxLOCAL dwOldProc:DWORD; 计算跳转偏移mov eax, offset HOOKCODEsub eax, g_pfnMessageBoxWsub eax, 5push eaxinvoke VirtualProtect, g_pfnMessageBoxW, 1, PAGE_EXECUTE_READWRITE, addr dwOldProc; 修改跳转pop eaxmov ebx, g_pfnMessageBoxWmov byte ptr [ebx], 0e9h ; jmpmov dword ptr [ebx 1], eaxinvoke VirtualProtect, g_pfnMessageBoxW, 1, dwOldProc, addr dwOldProcretInsertJmp endpRemoveJmp procLOCAL dwOldProc:DWORDinvoke VirtualProtect, g_pfnMessageBoxW, 1, PAGE_EXECUTE_READWRITE, addr dwOldProcmov ebx, g_pfnMessageBoxWmov byte ptr [ebx], 8bhmov dword ptr [ebx 1], 0ec8b55ffhinvoke VirtualProtect, g_pfnMessageBoxW, 1, dwOldProc, addr dwOldProcretRemoveJmp endpHOOKCODE:mov edi, edipush ebpmov ebp, espmov [ebp 10h], offset g_szNewTitle; 修复invoke RemoveJmp; 重入push MB_OKpush offset g_szNewTitlepush offset g_szNewTitlepush NULLcall g_pfnMessageBoxW; 修改invoke InsertJmpmov eax, g_pfnMessageBoxWadd eax, 5 jmp eaxInstallHook proc uses ebxLOCAL hUser32:HMODULELOCAL dwOldProc:DWORD; 获取 MessageBox 地址invoke GetModuleHandle, offset g_szUser32mov hUser32, eaxinvoke GetProcAddress, hUser32, offset g_szMessageBoxWmov g_pfnMessageBoxW, eaxinvoke InsertJmpretInstallHook endpDllMain proc hinstDll:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID.if fdwReason DLL_PROCESS_ATTACHinvoke InstallHook.endifmov eax, TRUEretDllMain endpend DllMain不过这种方法多次修改原 API 可能出现同步问题。一种解决方法是创建一个新的函数入口作为未被 Hook 的函数使用。 .586 .model flat,stdcall option casemap:noneinclude windows.inc include user32.inc include gdi32.inc include kernel32.incincludelib user32.lib includelib gdi32.lib includelib kernel32.lib.datag_szUser32 db user32,0g_szMessageBoxW db MessageBoxW, 0g_szNewTitle db 41h, 00h, 50h, 00h, 49h, 00h, 20h, 00h, 48h, 00h, 6Fh, 00h, 6Fh, 00h, 6Bh, 00h, 20h, 00h, 4Bh, 6Dh, 0D5h, 8Bh, 00h, 00hg_pfnMessageBoxW dd 0 .codeMyMessageBoxW proc hWnd:HWND, lpText:DWORD, lpCaption:DWORD, uType:DWORDmov eax, g_pfnMessageBoxWadd eax, 5 jmp eaxMyMessageBoxW endpHOOKCODE:mov edi, edipush ebpmov ebp, espmov [ebp 10h], offset g_szNewTitleinvoke MyMessageBoxW, NULL, offset g_szNewTitle, offset g_szNewTitle, MB_OKmov eax, g_pfnMessageBoxWadd eax, 5 jmp eaxInstallHook proc uses ebxLOCAL hUser32:HMODULELOCAL dwOldProc:DWORD; 获取 MessageBox 地址invoke GetModuleHandle, offset g_szUser32mov hUser32, eaxinvoke GetProcAddress, hUser32, offset g_szMessageBoxWmov g_pfnMessageBoxW, eax; 计算跳转偏移mov eax, offset HOOKCODEsub eax, g_pfnMessageBoxWsub eax, 5push eaxinvoke VirtualProtect, g_pfnMessageBoxW, 1, PAGE_EXECUTE_READWRITE, addr dwOldProc; 修改跳转pop eaxmov ebx, g_pfnMessageBoxWmov byte ptr [ebx], 0e9h ; jmpmov dword ptr [ebx 1], eaxinvoke VirtualProtect, g_pfnMessageBoxW, 1, dwOldProc, addr dwOldProcretInstallHook endpDllMain proc hinstDll:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID.if fdwReason DLL_PROCESS_ATTACHinvoke InstallHook.endifmov eax, TRUEretDllMain endpend DllMain异常筛选器 基本原理 筛选器异常即最终异常Windows 会为提供一个 API 来设置一个回调函数来处理异常这个 API 即 SetUnhandledExceptionFilter 具体定义如下 LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter );该函数的参数是一个函数指针即注册的异常处理的回调函数会被 UnhandledExceptionFilter 函数调用 LONG UnhandledExceptionFilter( STRUCT _EXCEPTION_POINTERS *ExceptionInfo );异常处理函数参数同样是一个 _EXCEPTION_POINTERS 类型的结构体指针_EXCEPTION_POINTERS 结构体定义如下 typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD, *PEXCEPTION_RECORD; typedef struct _EXCEPTION_POINTERS {PEXCEPTION_RECORD ExceptionRecord; PCONTEXT ContextRecord; } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;PEXCEPTION_RECORD ExceptionRecord指向 EXCEPTION_RECORD 结构体的指针。EXCEPTION_RECORD 结构体用于描述发生的异常的详细信息。 ExceptionCode异常代码表示特定类型的异常。ExceptionFlagsExceptionRecord与异常嵌套有关通常用不到。ExceptionAddress异常发生时的指令地址。NumberParametersExceptionInformation 中元素的个数。ExceptionInformation一个包含异常参数的数组只有 EXCEPTION_ACCESS_VIOLATION(0xC0000005) 异常时才会用的到此时 数组第一个元素是个读写标志位0 是读异常1 是写异常。数组第二个元素表示读写异常发生时读写的内存地址。 PCONTEXT ContextRecord指向 CONTEXT 结构体的指针。CONTEXT 结构体用于保存异常发生时的线程上下文包括寄存器值、堆栈指针等。 UnhandledExceptionFilter 的返回值有以下三种 // Defined values for the exception filter expression #define EXCEPTION_EXECUTE_HANDLER 1 #define EXCEPTION_CONTINUE_SEARCH 0 #define EXCEPTION_CONTINUE_EXECUTION (-1)EXCEPTION._EXECUTE_HANDLER表示该异常已经处理已经记录异常信息了进程可以结束了。EXCEPTION_CONTINUE_SEARCH表示不处理该异常请继续寻找其他处理程序。如果有调试器则交给调试器否则结束进程。EXCEPTION_CONTINUE_EXECUTION表示该异常已被修复请回到异常现场再次执行。 筛选器异常需要使用安装了 sharpOD 插件的 x64dbg 调试。 .386 .model flat, stdcall option casemap:NONEinclude windows.inc include user32.inc include gdi32.inc include kernel32.incincludelib user32.lib includelib gdi32.lib includelib kernel32.lib.datag_szMsg db 异常来了是否跳过异常代码, 0g_szMsg1 db 异常已被跳过, 0.codeMyUnhandledExceptionFilter proc pEP:ptr EXCEPTION_POINTERS LOCAL pEr:ptr EXCEPTION_RECORDLOCAL pCtx:ptr CONTEXTmov eax, pEPassume eax:ptr EXCEPTION_POINTERSmov ebx, [eax].pExceptionRecordmov pEr, ebxmov ebx, [eax].ContextRecordmov pCtx, ebxinvoke MessageBox, NULL, offset g_szMsg, NULL, MB_OKCANCEL.if eax IDOKmov ebx, pCtxassume ebx:ptr CONTEXTadd [ebx].regEip, 2assume ebx:nothingmov eax, EXCEPTION_CONTINUE_EXECUTION.elsemov eax, EXCEPTION_CONTINUE_SEARCH.endifretMyUnhandledExceptionFilter endpstart:invoke SetUnhandledExceptionFilter, offset MyUnhandledExceptionFiltermov eax, 123hmov dword ptr [eax], eaxinvoke MessageBox, NULL, offset g_szMsg1, NULL, MB_OKinvoke ExitProcess, 0end start自单步反软件断点 自单步反软件断点是利用单步异常在指令执行前来的特性检查每一条要执行的指令是否是 int3 断点来实现反调试。 .386 .model flat, stdcall option casemap:NONEinclude windows.inc include user32.inc include gdi32.inc include kernel32.incincludelib user32.lib includelib gdi32.lib includelib kernel32.lib.datag_szMsg db 异常来了是否跳过异常代码, 0g_szMsg1 db 未发现 INT3 断点, 0g_szTip db 发现 INT3 断点, 0.codeMyUnhandledExceptionFilter proc pEP:ptr EXCEPTION_POINTERS LOCAL pEr:ptr EXCEPTION_RECORDLOCAL pCtx:ptr CONTEXTmov eax, pEPassume eax:ptr EXCEPTION_POINTERSmov ebx, [eax].pExceptionRecordmov pEr, ebxmov ebx, [eax].ContextRecordmov pCtx, ebxmov ebx, pErassume ebx:ptr EXCEPTION_RECORDmov esi, pCtxassume esi:ptr CONTEXT.if [ebx].ExceptionCode EXCEPTION_ACCESS_VIOLATIONadd [esi].regEip, 2or [esi].regFlag, 100h.elseif [ebx].ExceptionCode EXCEPTION_SINGLE_STEPmov eax, [esi].regEip.if byte ptr [eax] 0cchinvoke MessageBox, NULL, offset g_szTip, NULL, MB_OKmov eax, EXCEPTION_EXECUTE_HANDLERret.endif.if [esi].regEip ! offset CODE_ENDor [esi].regFlag, 100h.endif.endifassume esi:nothingassume ebx:nothingmov eax, EXCEPTION_CONTINUE_EXECUTIONretMyUnhandledExceptionFilter endpstart:invoke SetUnhandledExceptionFilter, offset MyUnhandledExceptionFiltermov eax, 123hmov dword ptr [eax], eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxxor eax, eaxCODE_END:invoke MessageBox, NULL, offset g_szMsg1, NULL, MB_OKinvoke ExitProcess, 0end start如果下完断点之后直接继续执行那么在异常中设置的设置的单步异常不会被调试器接管后清除因此程序的异常处理函数会检查指令从而发现断点。 如果是在调试器中单步调试单步步过第一条异常指令避免进入异常处理函数设置单步异常那么后续程序就无法自动为每条指令设置单步异常。并且调试器单步时设置的单步异常会在调试器接管单步异常之后清除因此此时该反调试方法失效。 OD 插件 前面调试筛选器异常的时候如果使用 OD 会出现异常交给 OD 后被 OD 处理了而没有交给程序的情况导致程序执行流程与实际不符无法调试异常处理函数。 这里我们实现一个 OD 插件通过修改关键跳转使得筛选器异常直接交给程序而不是交给调试器从而实现对筛选器异常处理函数的调试。 实际调试发现我的环境中的 KernelBase.dll 中的 UnhandledExceptionFilter 函数中调用 BasepIsDebugPortPresent 函数判断是否存在调试器之后存在一个关键跳转。只要我们将该跳转的 jnz 修改为 jz 就可以确保筛选器异常不会交给调试器。 if ( BasepIsDebugPortPresent() )return 0;.text:10212791 E8 E7 FB FF FF call _BasepIsDebugPortPresent0 ; BasepIsDebugPortPresent() .text:10212791 .text:10212796 85 C0 test eax, eax .text:10212798 0F 85 E8 00 00 00 jnz loc_10212886插件代码如下OD 插件实在加载不上去就鸽了 // dllmain.cpp : 定义 DLL 应用程序的入口点。 #include pch.h #include Plugin.h#pragma comment(lib, Ollydbg.lib)int ODBG_Plugindata(char* shortname) {strcpy_s(shortname, 31, MyOdPlug);return PLUGIN_VERSION; }int ODBG_Plugininit(int ollydbgversion, HWND hw, ulong* features) {return 0; }int ODBG_Paused(int reason, t_reg* reg) {if (reason PP_EVENT) {HMODULE hKernel GetModuleHandleA(kernelbase.dll);LPBYTE pAddr (LPBYTE) GetProcAddress(hKernel, UnhandledExceptionFilter);pAddr 0xA8;BYTE btCode 0x84;Writememory(btCode, (ulong) pAddr, sizeof(btCode), MM_SILENT);}return NULL; }BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) {switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE; }
http://www.pierceye.com/news/778754/

相关文章:

  • 网站前端用的到ps做教育app的网站有哪些
  • 有没有兼职做网站的低价自适应网站建设
  • 文成网站建设所有关键词
  • 吉林市做网站哪家好建网站的方法
  • 北京做网站的怎样用自己的服务器建设网站
  • 镇江建设局网站开发公司采购招聘
  • 阿里云编辑建设好的网站凡客官网登录入口网址
  • 后盾网原创实战网站建设教程北京app网站建设价格
  • 简述网站建设过程步骤wordpress英文建站
  • 网站开发 mvc有孩子做的网站
  • 自己做的网站如何推广wordpress 主题页脚
  • 数据库型网站怎么把电脑当服务器做网站
  • 东莞网站建设品牌公司如何做电子书网站
  • 免费学做美食视频网站有哪些百度是国企还是央企
  • wordpress 网站关键词设置wordpress 上传主机
  • h5电子商务网站如何查询关键词的搜索量
  • 网站导航栏兼容性网站建设的主要技术指什么软件
  • 如何抄袭网站400靓号手机网站建设
  • 大兴网站建设价格怎样建设好网站
  • 三维家是在网站上做还是在app上国内新闻最新5条
  • 呼伦贝尔网站设计wordpress如何关闭主题
  • 苏州网站制作网站建设淮安住房和城乡建设厅网站
  • 房产中介网站wordpress模板mip
  • 汽车租赁网站怎么做沈阳网站开发程序员工资
  • 网站建设教程搭建汽岁湖南岚鸿专注交城有做网站的吗
  • 网站开发怎么连接sqlserver建设网站怎么收费标准
  • 万网网站模板购买北京南站核酸检测地点
  • 南京城乡建设网站公司做网站哪个好
  • 有没有学做衣服的网站广告设计公司有什么岗位
  • 什么网站做免单衣服厦门设计师网站