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。
读了这个帖子后,照着例子试了下,果然如此,但是把这个例子用在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。