js npapii使用embed 调用dll插件_OD插件编写

OD的bug

OD的异常bug

当程序产生了异常后,操作系统在派发异常时,首先会将异常给调试器,但是在调试过程中,OD并不能成功收到异常,需要手动对 kernel32.dll中的 UnhandledExceptionFilter打补丁才能解决这个问题或者使用 SharpOD插件。

手动修复Bug

手动修改流程,使其可以执行下面的函数调用。

56750305e145e544a7ccfaea89554b6b.png

Win10环境下

UnhandledExceptionFilter API中偏移为 C9的位置修改为 xor eax,eax

d72442b66d501e40bffcf487d8f804db.png

Win7环境下

定位到 kernel32.dll中的 UnhandledExceptionFilter中的偏移为 54的位置,将下图中的 test eax,eax改为 xor eax,eax即可避免其在分发的时候,跳过后面的大段代码。

be7765a83389e62f218c1f688fdaeb07.png

Xp环境下

定位到 kernel32.dll中的 UnhandledExceptionFilter中的偏移为 8F的位置,将 test eax,eax后面的 jl改成 jmp,可以修复这个bug。

d069977f32d9b99ebf10217a258919e8.png

08_2

OD窗口回调函数显示bug

OD可以遍历被调试进程的所有窗口,并显示窗口的的相关信息。

一般分析窗口时需要找到窗口对应的回调函数,在里面进行分析。

OD加载进程 查看->窗口打开窗口后,窗口回调函数的地址显示不正常,超过 80000000为操作系统的地址空间。

6320ba279855e764161f73420af82051.png

分析BUG

分析OD会通过 GetClassLong来获取窗口信息,用OD加载OD后, Alt+E,选中主模块,右键菜单 查看名称,首先在 GetClassLong的每个参考上设置断点。

用spy++查看计算器的窗口信息

5cd5ddc441221a0cfa649519739845da.png

在被调试的OD中 查看->窗口,在右键菜单中,选择刷新,此时OD调试器的断点断下

0c512287f85acb14adafc07c6e6eea47.png

查看堆栈窗口的信息,发现获取的为计算器的窗口,返回到调用处,在调用处下断点,断下后F8单步步过,查看返回值。

0557a10425db387192db1764562a6d0e.png

发现其返回值错误。

分析原因

窗口分ASCII版本和UNICODE版本,而OD中只使用了 GetClassLongA所以遇到UNICODE版本的程序就没有办法获取成功了,而计算器的窗口为Unicode版本的。

fa01751cfe4272b3486edc802a65d982.png

解决方案

自己写一个判断程序,判断要打开的窗口是UNICODE的版本还是ASCII版本

912280cb5bad36d55a202854f85020b5.png

然后修改跳转表中对应位置 50D858的值,为正确的 GetWindowLongAPI的地址。

编写OD插件

插件是以动态链接库形式存在,导出必要函数后,放入plugin文件夹下即可。

OD在启动时,会遍历plugin目录下的所有dll,当DLL中导出了 ODBG_PlugindataODBG_Pluginit函数后,才会被当作插件来加载

通过查看OD插件帮助文档来调用对应的接口。

  • intODBG_Plugindata(char*shortname);//[OUT]shortname最长为32位字符串的指针为插件名称,显示在插件菜单中。

  • intODBG_Plugininit(intollydbgversion,HWND hw,ulong*features);//必须回调函数。在一个有效的 OllyDbg 插件中必须使用它,你可以将所有需要初始化和分配的资源放在这个函数里。如果启动成功,函数必须返回 0,发生错误返回 -1,那样插件就会卸载,参数 ollydbgversion 是插件可以兼容的OllyDbg的版本号。

  • intODBG_Paused(intreason,t_reg*reg)//选回调函数。OllyDbg 在被调试程序暂停时或一个内部进程完成时调用本函数。

未设置字符数据类型错误

5f8cb2c9dcec8c2c41c2af2ae97c9b7a.png

在头文件中有说明。

acea0393360641c938668536a5b581b8.png

在编译选项中添加 /J选项即可解决。

d38a5283c3594b24b11e05299ddc67fa.png

在Plugin.h头文件中,定义了常用的导出函数,不需要手动导出。

436328ce99542a1a3c5533ce184ed1bd.png

有可能会和已经安装的别的插件发生冲突,测试时只保留我们的插件来进行测试。

使用 ODBG_Paused时进行修改。

// dllmain.cpp : 定义 DLL 应用程序的入口点。#include "pch.h"#include "Plugin.h"#pragma comment(lib,"Ollydbg.lib")//包含lib文件int ODBG_Plugindata(char* shortname){    strcpy(shortname, "flag0Plugin");    return PLUGIN_VERSION;}int ODBG_Paused(int reason, t_reg* reg){    if (reason == PP_EVENT )    {        //1. 获取kernel32.UnhandleExceptionFilter的地址        HMODULE hModKer = GetModuleHandle("Kernel32");        PBYTE pUEFAddr = (PBYTE)GetProcAddress(hModKer, "UnhandledExceptionFilter");        //2. 定位jl xxxx的地址        PBYTE pJlAddr = pUEFAddr + 0x8F;        //3. 将jl修改为jmp        //E9 00000000        //90        char aryCode[] = { '\xe9', '\xa3','\x00','\x00' ,'\x00' ,'\x00','\x90' };        //修改被调试进程的内存        Writememory(aryCode, (ulong)pJlAddr, sizeof(aryCode), MM_SILENT);    }    return 1;//允许调用go}DWORD WINAPI MyGetClassLong(HWND hWnd, int nIndex){    if (IsWindowUnicode(hWnd))    {        return GetClassLongW(hWnd, nIndex);    }    else    {        return GetClassLongA(hWnd, nIndex);    }}int ODBG_Plugininit(int ollydbgversion, HWND hw, ulong* features){    //修改OD自身    DWORD dwOldprotect = 0;    PBYTE pOldAddr = (PBYTE)0x50D858;    VirtualProtect(pOldAddr, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldprotect);    *(PDWORD)pOldAddr = (DWORD)MyGetClassLong;    VirtualProtect(pOldAddr, sizeof(DWORD), dwOldprotect, &dwOldprotect);    return 0;}BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved){    return TRUE;}

如何定位OD中API的位置

  1. 通过 LoadLibrary, GetProcAddress,来定位。

  2. 通过查找特征码。

特征码:是一段唯一的二进制数值,通过遍历模块的内存对比的方式来定位函数。

使用特征码的场景,是应用于函数没有导出的情况。

OD 脚本和插件的区别

OD脚本可以直接在OD上跑,每次都要手动执行,插件是由OD启动时自动加载的用于增强功能的,脚本用来自动化,来解决重复劳动。

X64dbg的脚本可以python编写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值