在RELEASE版本中快速定位DATA ABORT的方法

简介:

首先在DEBUG版本中定位DATA ABORT的方法,地球人应该都知道了吧,我就不废话了。PlatformBuilder或VS2005、EVC这类IDE工具会在DEBUG模式下自动停在出错的那句,情况就很显然了。

RELEASE版本下的泄漏就要稍微麻烦一点,如何快速定位呢?


案例一:用EVC编译的应用程序泄漏

首先我做了一个内存泄漏的程序walzer_leak.exe,里面做了一个泄漏的函数
void DoLeak()

    int* p = (int*)0x81000000;
    *p = 10;
}

编译的时候注意先在project settings里的Link页里勾选“Generate mapfile”,会生成一个map文件。如下图


把编译出来的RELEASE版本可执行文件放到CE5平台下运行。出错的时候串口打印了一句

Data Abort: Thread=83ad1d38 Proc=820266d0 'walzer_leak.exe'
AKY=00000021 PC=00011008(walzer_leak.exe+0x00001008) RA=00011030(walzer_leak.exe+0x00001030) BVA=81000000 FSR=0000000d

这句是系统自动输出的。我们得到了一个关键的信息:PC指针。和PC指针在walzer_leak.exe中的偏移量。然后打开编译时生成的walzer_leak.map文件
,文件不长,我贴一下

************************************************************
Walzer_leak

 Timestamp is 46fcbb17 (Fri Sep 28 16:28:07 2007)

 Preferred load address is 00010000

 Start         Length     Name                   Class
 0001:00000000 00000258H .text                   CODE
 0002:00000000 00000014H .xdata                  DATA
 0002:00000014 00000014H .idata$2                DATA
 0002:00000028 00000014H .idata$3                DATA
 0002:0000003c 00000010H .idata$4                DATA
 0002:0000004c 0000000cH .idata$6                DATA
 0002:00000058 00000000H .edata                  DATA
 0003:00000000 00000010H .idata$5                DATA
 0003:00000010 00000004H .CRT$XCA                DATA
 0003:00000014 00000004H .CRT$XCZ                DATA
 0003:00000018 00000004H .CRT$XIA                DATA
 0003:0000001c 00000004H .CRT$XIZ                DATA
 0003:00000020 00000004H .CRT$XPA                DATA
 0003:00000024 00000004H .CRT$XPZ                DATA
 0003:00000028 00000004H .CRT$XTA                DATA
 0003:0000002c 00000004H .CRT$XTZ                DATA
 0003:00000030 00000009H .bss                    DATA
 0004:00000000 00000038H .pdata                  DATA
 0005:00000000 00000010H .rsrc$01                DATA
 0005:00000010 00000000H .rsrc$02                DATA

  Address         Publics by Value              Rva+Base     Lib:Object

 0001:00000000       ?DoLeak@@YAXXZ             00011000 f   Walzer_leak.obj
 0001:00000010       WinMain                    00011010 f   Walzer_leak.obj
 0001:0000002c       WinMainCRTStartup          0001102c f   corelibc:pegwmain.obj
 0001:000000a0       _cinit                     000110a0 f   corelibc:crt0dat.obj
 0001:00000210       exit                       00011210 f   corelibc:crt0dat.obj
 0001:00000228       _XcptFilter                00011228 f   coredll:COREDLL.dll
 0001:00000238       __C_specific_handler       00011238 f   coredll:COREDLL.dll
 0001:00000248       LocalFree                  00011248 f   coredll:COREDLL.dll
 0002:00000014       __IMPORT_DESCRIPTOR_COREDLL 00012014     coredll:COREDLL.dll
 0002:00000028       __NULL_IMPORT_DESCRIPTOR   00012028     coredll:COREDLL.dll
 0003:00000000       __imp___C_specific_handler 00013000     coredll:COREDLL.dll
 0003:00000004       __imp_LocalFree            00013004     coredll:COREDLL.dll
 0003:00000008       __imp__XcptFilter          00013008     coredll:COREDLL.dll
 0003:0000000c       \177COREDLL_NULL_THUNK_DATA 0001300c     coredll:COREDLL.dll
 0003:00000010       __xc_a                     00013010     corelibc:crt0init.obj
 0003:00000014       __xc_z                     00013014     corelibc:crt0init.obj
 0003:00000018       __xi_a                     00013018     corelibc:crt0init.obj
 0003:0000001c       __xi_z                     0001301c     corelibc:crt0init.obj
 0003:00000020       __xp_a                     00013020     corelibc:crt0init.obj
 0003:00000024       __xp_z                     00013024     corelibc:crt0init.obj
 0003:00000028       __xt_a                     00013028     corelibc:crt0init.obj
 0003:0000002c       __xt_z                     0001302c     corelibc:crt0init.obj
 0003:00000030       __onexitend                00013030     <common>
 0003:00000034       __onexitbegin              00013034     <common>
 0003:00000038       _exitflag                  00013038     <common>

 entry point at        0001:0000002c

 Static symbols

 0001:0000010c       doexit                     0001110c f   corelibc:crt0dat.obj
************************************************************

OK,首先,里面有一句“Preferred load address is 00010000”,这意味着DATA ABORT那句的PC=00011008(walzer_leak.exe+0x00001008) 我们必须把括

号里的0x1008加上这个load address的偏移量,得到0x11008(注意不能直接用PC,一会儿再给个案例就知道了),然后我们在函数偏移列表里看Rva+Base

这栏,找到0x11008落在了DoLeak函数的地址范围里,所以是DoLeak函数泄漏了。


案例二:在OAL层做了一个泄漏的函数,用Platform Builder进行RELEASE版编译并LINK到NK.exe里,然后应用程序Call_Leak.exe调用该函数导致泄漏

步骤类似,只是Platform Builder默认就会在RELEASE目录下生成.map文件。应用程序去调用泄漏的OAL函数时,出现

Data Abort: Thread=822fc000 Proc=820267c0 'Call_Leak.exe'
AKY=00000041 PC=8023e3c8(NK.EXE+0x0003e3c8) RA=8023e1d4(NK.EXE+0x0003e1d4) 
BVA=8e000000 FSR=00000005

注意我们这次是NK.EXE里制造泄漏,所以PC指针不是在0x00011008这样的Slot 0低地址了,而是在0x80000000以上的KERNEL区域了。
nk.map很长,我选择关键段落来贴

************************************************************
 kern

 Timestamp is 46fca696 (Fri Sep 28 15:00:38 2007)

 Preferred load address is 00010000

 ...
 0001:0003d2c8       OALIoCtlHal_GetDeviceId    0004e2c8 f   oal_ioctl:deviceid.obj
 0001:0003d398       OALIoCtlHal_DoLeak    0004e398 f   oal_ioctl:leaktest.obj
 0001:0003d438       OALIoCtlHal_DdkCall        0004e438 f   oal_io:ioctl.obj
 ...
************************************************************

所以 NK.EXE + 0x0003e3c8 = 0x10000(Preferred load address) + 0x0003e3c8 = 0x4e3c8, 落在了OALIoCtlHal_DoLeak函数里


结论:原理上很简单,就是利用DATA ABORT消息中的PC值,配合MAP文件可以快速定位到泄漏的函数。定位到之后,嘿嘿,谁LEAK谁请客咯。

-------------------------------
10月11日补充:

用上文的方法,不但网友kevin没有成功定位到泄漏的原因(见后面回帖,他定位到微软USBFN的MDD层代码),我这项目组里的人也没抓到原因(定位到PRIVATE下LoadLibrary函数相关的代码)。昨晚我想了下,这个方法的确有漏洞,早上我做了个试验,建立个DialogBox,主处理函数如下

static DWORD* g_pTest = NULL;

int CALLBACK LeakProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_INITDIALOG:
        g_pTest = (DWORD*)malloc(1);
        break;
    case WM_COMMAND:
        switch(wParam)
        {
        case ID_LEAK:
            *((int*)0x1A013860) = 0x1C000000;
            break;
        case ID_CLOSE:
            if(g_pTest)
            {
                *g_pTest = 1;
            }
            EndDialog(hDlg, 0);
            break;
        }
        break;
     }
     return FALSE;
}

我运行了几次,每次该进程的BaseAddr = 0x1A000000, 而 &g_pTest = 0x1A013860,在进程的全局变量区;malloc之后g_pTest = 0x00030230在进程的堆区。所以我
(1) 在ID_LEAK按钮按下后,模拟一次内存泄漏,直接对&g_pTest地址上的数值改写,把malloc后的0x00030230改成0x00000000, 注意虽然该处已经泄漏了,但是并没有产生data abort exception.
(2) 然后在ID_CLOSE按钮按下后,装做不知道前面那处泄漏,代码风格严谨地先判断下指针是否为空,然后试图在malloc得到的堆区0x00030230地址上写个值,但是由于g_pTest这个指针已经被改写为指向其他进程空间了,所以在*g_pTest = 1这句产生data abort exception并停下来了。
(3) 所以,按照上文的方法,只能抓到*g_pTest = 1这句泄露,而实际上这句是无辜的,真正的元凶*((int*)0x1A013860) = 0x1C000000这句却没有被抓出来。



本文转自Walzer博客园博客,原文链接:http://www.cnblogs.com/walzer/archive/2007/09/28/909626.html,如需转载请自行联系原作者


相关文章
|
Windows
windows 技巧篇-解除共享文件夹占用方法,解决共享文件被占用导致不可修改问题,查看共享文件被谁占用方法
windows 技巧篇-解除共享文件夹占用方法,解决共享文件被占用导致不可修改问题,查看共享文件被谁占用方法
2673 0
windows 技巧篇-解除共享文件夹占用方法,解决共享文件被占用导致不可修改问题,查看共享文件被谁占用方法
|
存储 缓存 NoSQL
《Redis缓存:高性能数据存储的奥秘与多元应用》
Redis是一款基于内存的高性能键值对存储系统,凭借极快的读写速度成为提升应用性能的关键技术。它通过缓存热点数据减少数据库压力,结合LRU/LFU等淘汰策略优化内存使用。在电商领域,Redis加速商品详情页加载、保障秒杀活动高并发处理;在社交媒体中,支持实时点赞、评论和在线状态更新;游戏行业利用Redis管理玩家进度与排行榜;CDN场景下,Redis缓存热门内容降低延迟;分布式系统中,Redis实现数据共享与分布式锁功能。作为高效的数据管家,Redis正为数字化世界提供强大支撑。
357 2
|
Linux 编译器 开发工具
【Linux快速入门(三)】Linux与ROS学习之编译基础(Cmake编译)
【Linux快速入门(三)】Linux与ROS学习之编译基础(Cmake编译)
866 2
|
Java API Maven
如何使用Java开发抖音API接口?
在数字化时代,社交媒体平台如抖音成为生活的重要部分。本文详细介绍了如何用Java开发抖音API接口,从创建开发者账号、申请API权限、准备开发环境,到编写代码、测试运行及注意事项,全面覆盖了整个开发流程。
2391 10
|
10月前
|
机器学习/深度学习 人工智能 JSON
AI操作网页:browser-use和AI大模型互动解析
browser-use 是一个开源的 AI 驱动浏览器自动化框架,能够高效实现在线任务自动化,支持 AI 大模型操作网页,具备强大的社区影响力(GitHub 星数超 63.4k)。它通过精巧的 prompt 设计和多类型消息组合,实现与大模型的高效交互,可完成登录、数据提取、文档生成等复杂任务。其核心技巧包括结构化输入输出、任务拆解、历史记忆管理及多模态支持,为 AI 代理应用提供实践范例与技术启发。
|
网络安全 开发工具 数据安全/隐私保护
自建内网穿透服务器
本文介绍了如何使用FRP实现内网穿透。首先准备一台具有公网IP的云服务器和一台内网服务器,接着在云服务器上安装Docker和FRP服务端,配置`frps.ini`文件并启动服务。在内网服务器上手动安装FRP客户端,配置`frpc.ini`文件并启动服务。最后通过FRP控制台验证连接状态,确保可以通过公网IP访问内网服务。
5077 10
自建内网穿透服务器
|
存储 缓存 编解码
FFmpeg开发笔记(四):ffmpeg解码的基本流程详解
FFmpeg开发笔记(四):ffmpeg解码的基本流程详解
FFmpeg开发笔记(四):ffmpeg解码的基本流程详解
|
存储 编译器 C++
【C++】:拷贝构造函数和赋值运算符重载
【C++】:拷贝构造函数和赋值运算符重载
276 1
|
SQL 安全 关系型数据库
【惊天秘密】破解数据库管理难题!——Yearning开源审计平台:你的数据库安全守护神,一键审计,轻松应对挑战!
【8月更文挑战第21天】Yearning是一款基于Python的开源数据库审计平台,简化数据库管理和审计流程,支持MySQL、PostgreSQL等。核心功能包括SQL审计、执行、回滚及备份,提升数据库管理效率。安装简便,支持通过pip安装并快速启动服务。Yearning提供智能SQL审查,确保安全性与合规性,同时还具备友好的用户界面及API客户端支持,适用于多种数据库操作场景。
1242 0
|
机器学习/深度学习 人工智能 自然语言处理
大模型和传统ai的区别
在人工智能(AI)领域,大模型一直是一个热议的话题。从之前的谷歌 DeepMind、百度 Big. AI等,再到今天的百度GPT-3,人工智能技术经历了从“有”到“大”的转变。那么,大模型与传统 ai的区别在哪里?这对未来人工智能发展会产生什么影响?

热门文章

最新文章