读“如何通过崩溃地址找到出错的代码行”有疑问,继续挖掘一下,求查dll代码的方法。(200分)

  • 主题发起人 FreeAndNil
  • 开始时间
F

FreeAndNil

Unregistered / Unconfirmed
GUEST, unregistred user!
源帖:http://www.delphibbs.com/keylife/iblog_show.asp?xid=30762

读了这个帖子后,照着例子试了下,果然如此,但是把这个例子用在dll中报的异常,却不能获得正确的崩溃行偏移,研究了一下,应该是和基地址(ImageBase Address)有关,经过测试,发现dll的基地址不是固定的,学知甚浅,不明白其中原因,来求问。

写了个测试程序,就是上面笔记中的例子,代码放在dll中,运行报错:
---------------------------
Project1: Project1.exe - 应用程序错误
---------------------------
"0x014e0267" 指令引用的 "0x014e01dc" 内存。该内存不能为 "written"。


要终止程序,请单击“确定”。
要调试程序,请单击“取消”。
---------------------------
确定 取消
---------------------------

第一个错误提示中的0x014e0267就是程序的崩溃地址,根据崩溃行偏移公式,要减去基地址,但这个基地址不是0x00400000。
点确定后,delphi还会出一个错误提示:
---------------------------
Application Error
---------------------------
Exception EAccessViolation in module Project2.dll at 00020267.

Access violation at address 014E0267 in module 'Project2.dll'. Write of address 014E01DC.


---------------------------
确定
---------------------------

里面还有个地址:00020267,其实这个地址就是“崩溃地址(Crash Address) - 基地址(ImageBase Address)”得到的值,由此可推出,此时的基地址是14C0000,但这个程序在其他人机器上运行,崩溃地址就不同了,推算出来的基地址是24D0000,而且,在其他项目中加入产生异常的代码,报的地址错误,推算出来的基地址又是其他值,而且,也不报第二个异常,比如我在项目中添加一个按钮,直接往未初始化的指针里写数据,结果报异常:
---------------------------
xxxxx
---------------------------
Access violation at address 05A4772A in module 'C_SETTLE.DLL'. Write of address 400058CB.
---------------------------
确定
---------------------------
并没有报“崩溃地址(Crash Address) - 基地址(ImageBase Address)”后的异常地址,这样,根据崩溃地址,就无法获得代码行的信息,其主要原因是基地址得不到,在dll的project option里的linker页面中,Image Address也是$00400000,但是显然不能把这个值用在公式中,而exe的project option里的linker页面中的Image Address,可以修改,修改后,exe崩溃计算公式就应该用修改后的基地址了,不懂,来请教一下了。

exe:
崩溃行偏移 = 崩溃地址 - 0x00400000 - 0x1000
dll:
崩溃行偏移 = 崩溃地址 - ?????????? - 0x1000


例子:
exe:

program Project1;

uses
windows,
Forms,
Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

var
dHandle: THandle;
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
dHandle := LoadLibrary('Project2.dll');
Application.Run;
end.

dll:
library Project2;

uses
SysUtils,
Classes;

{$R *.res}

var
i,j:real;
ss:string;
aa: ^integer;
begin
i:=1;
j:=1;
i:=i/j;
ss:=CurrToStr(i);
aa := nil;
aa^ := 100;
i:=i/aa^;
ss:=CurrToStr(i);
end.

project option里的linker页面中的map file选detailed。
 
没有接触过累世的问题,但是可以学C的Assert,调式麻!
 
可以查看Modules窗口,里头列出用到的DLL中会列出DLL的基地址吧?
 
dll 也是delphi的
你干吗不 直接断点 跟踪
 
Passion,Modules窗口是?

hfghfghfg,如果程序已经交付给别人用了,报AV错,只能提供出错地址,那这个方法就很有用了。
 
调入dLL,返回的句柄就是基地址
哈哈
 
如果 别人 用 OllyDBG 不就可以了吗?
[:D]
 
接受答案了.
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
619
import
I
顶部