📄 symbolhandler.pas.svn-base
字号:
end;
modulelistMREW.endread;
end;
function TSymhandler.getmodulebyname(modulename: string; var mi: TModuleInfo):BOOLEAN;
var i: integer;
begin
result:=false;
modulelistMREW.beginread;
for i:=0 to modulelistpos-1 do
if (uppercase(modulelist[i].modulename)=uppercase(modulename)) then
begin
mi:=modulelist[i];
result:=true;
break;
end;
modulelistMREW.endread;
end;
function TSymHandler.getsearchpath:string;
var sp: pchar;
begin
getmem(sp,4096);
if isloaded then
begin
if SymGetSearchPath(processhandle,sp,4096) then
begin
result:=sp;
end
else result:='';
end;
end;
procedure TSymHandler.setsearchpath(path:string);
begin
if isloaded then
symsetsearchpath(processhandle,pchar(path));
searchpath:=path;
end;
function TSymhandler.getNameFromAddress(address:dword;symbols:boolean; modules: boolean):string;
var symbol :PImagehlpSymbol;
offset: dword;
s: string;
mi: tmoduleinfo;
processhandle: thandle;
begin
{$ifdef autoassemblerdll}
processhandle:=symbolhandler.processhandle;
{$else}
if targetself then
begin
processhandle:=getcurrentprocess;
end
else
begin
processhandle:=cefuncproc.ProcessHandle;
end;
{$endif}
if symbols then
begin
//first see if it is a symbol
symbolloadervalid.beginread;
try
if (symbolloaderthread<>nil) then
begin
if isloaded then
begin
getmem(symbol,sizeof(IMAGEHLP_SYMBOL)+255);
try
zeromemory(symbol,sizeof(IMAGEHLP_SYMBOL)+255);
symbol.SizeOfStruct:=sizeof(IMAGEHLP_SYMBOL)+255;
symbol.MaxNameLength:=254;
if SymGetSymFromAddr(processhandle,address,@offset,symbol^) then
begin
//found it
s:=pchar(@symbol.Name[0]);
if offset=0 then
result:=s
else
result:=s+'+'+inttohex(offset,1);
exit;
end;
finally
freemem(symbol);
end;
end;
end;
finally
symbolloadervalid.endread;
end;
//check the userdefined symbols
result:=self.GetUserdefinedSymbolByAddress(address);
if result<>'' then exit;
end;
if modules then
begin
//get the dllname+offset
if getmodulebyaddress(address,mi) then
begin
if address-mi.baseaddress=0 then
result:=mi.modulename
else
result:=mi.modulename+'+'+inttohex(address-mi.baseaddress,1);
exit;
end;
end;
result:=inttohex(address,8); //default
end;
function TSymhandler.getNameFromAddress(address:dword):string;
begin
result:=getNameFromAddress(address,self.showsymbols,self.showmodules);
end;
function TSymhandler.getAddressFromName(name:string):dword;
begin
result:=getAddressFromName(name,true);
end;
function TSymhandler.getAddressFromName(name: string; waitforsymbols: boolean):dword;
var mi: tmoduleinfo;
newaddress: string;
symbol :PImagehlpSymbol;
oldoptions: dword;
offset: dword;
sn: string;
i: integer;
ws: widestring;
pws: pwidechar;
error: boolean;
processhandle: thandle;
begin
{$ifdef autoassemblerdll}
processhandle:=symbolhandler.processhandle;
{$else}
if targetself then
begin
processhandle:=getcurrentprocess;
end
else
begin
processhandle:=cefuncproc.ProcessHandle;
end;
{$endif}
result:=0;
val(ConvertHexStrToRealStr(name),result,i);
if i=0 then exit; //it's a valid hexadecimal string
try
//first cut of the name from the offset
offset:=0;
for i:=length(name) downto 1 do
if name[i] in ['+','-'] then
begin
sn:=copy(name,i+1,length(name));
offset:=strtoint('$'+sn);
if name[i]='-' then
offset:=-offset;
name:=copy(name,1,i-1);
break;
end
else
if name[i] in ['[',']'] then
break;
except
raise symexception.create(sn+' is not a valid value');
end;
if name='' then name:='0';
val('$'+name,result,i);
if i=0 then
begin
result:=result+offset;
exit; //it was a simple +/- calculation
end;
{
debugger hell:
tools->debugger options->Language Exceptions
click add...
type in "symexception" without the quotes
this will cause you to still break on normal exception like memory access violations, but not on these
}
if getreg(uppercase(name),false)<>9 then
raise symexception.create('Register'); //can happen in case of eax+# //speed improvement
//see if it is a module
if getmodulebyname(name,mi) then
result:=mi.baseaddress+offset
else
begin
//if not, see if you can find it as a symbol
//first check the userdefined symbols (small list, so faster than the symbols)
result:=GetUserdefinedSymbolByName(name);
if result<>0 then
begin
result:=result+offset;
exit;
end;
{$ifndef autoassemblerdll}
if (darkbytekernel<>0) and (length(name)>6) and (pos('KERNEL_',uppercase(name))>0) then
begin
name:=copy(name,8,length(name)-7);
ws:=name;
pws:=@ws[1];
result:=dword(GetKProcAddress(pws));
if result<>0 then
begin
result:=result+offset;
exit;
end;
end;
{$endif}
{ 5.4: check if it is a pointer notation }
result:=GetAddressFromPointer(name,error);
if not error then
begin
result:=result+offset;
exit;
end;
{ 5.4 ^^^ }
symbolloadervalid.beginread;
try
if (symbolloaderthread<>nil) then
begin
if symbolloaderthread.isloading and not waitforsymbols then
raise symexception.create('This is not a valid address');
symbolloaderthread.WaitFor; //wait for it to finish if it's still busy
//it's not a valid address, it's not a calculation, it's not a modulename+offset, so lets see if it's a module
getmem(symbol,sizeof(IMAGEHLP_SYMBOL)+255);
try
zeromemory(symbol,sizeof(IMAGEHLP_SYMBOL)+255);
symbol.SizeOfStruct:=sizeof(IMAGEHLP_SYMBOL)+255;
symbol.MaxNameLength:=254;
if SymGetSymFromName(processhandle,pchar(name),symbol^) then
result:=symbol.Address+offset
else
raise symexception.Create('This is not a valid address'); //no hex string, no module, no symbol, so invalid
finally
freemem(symbol);
end;
end else
raise symexception.Create('This is not a valid address');
finally
symbolloadervalid.endread;
end;
end;
end;
procedure TSymhandler.loadmodulelist;
var
ths: thandle;
me32:MODULEENTRY32;
x: pchar;
processid: dword;
begin
{$ifdef autoassemblerdll}
processid:=symbolhandler.ProcessID;
{$else}
if targetself then
processid:=getcurrentprocessid
else
processid:=cefuncproc.ProcessID;
{$endif}
modulelistMREW.BeginWrite;
try
modulelistpos:=0;
if processid=0 then exit;
//refresh the module list
ths:=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,processid);
if ths<>0 then
begin
me32.dwSize:=sizeof(MODULEENTRY32);
if ths<>0 then
begin
try
if module32first(ths,me32) then
repeat
if modulelistpos+1>=length(modulelist) then
setlength(modulelist,length(modulelist)*2);
x:=me32.szExePath;
modulelist[modulelistpos].modulename:=extractfilename(x);
modulelist[modulelistpos].baseaddress:=dword(me32.modBaseAddr);
modulelist[modulelistpos].basesize:=me32.modBaseSize;
inc(modulelistpos);
until not module32next(ths,me32);
finally
closehandle(ths);
end;
end;
end;
finally
modulelistmrew.EndWrite;
end;
end;
function TSymhandler.GetAddressFromPointer(s: string; var error: boolean):dword;
{
Will return the address of a pointer noted as [[[xxx+xx]+xx]+xx]+xx
If it is a invalid pointer, or can not be resolved, the result is NULL
}
var i: integer;
list: tstringlist;
offsets: array of dword;
baseaddress: dword;
off: string;
realaddress, realaddress2: dword;
check: boolean;
count: dword;
begin
result:=0;
error:=true;
list:=tstringlist.create;
try
if not ParseAsPointer(s,list) then exit;
try
baseaddress:=getaddressfromname(list[0]);
except
exit;
end;
setlength(offsets,list.count-1);
for i:=1 to list.Count-1 do //start from the first offset
begin
off:=copy(list[i],2,length(list[i]));
try
offsets[i-1]:=strtoint('$'+off);
except
exit;
end;
if list[i][1]='-' then
offsets[i-1]:=-offsets[i-1];
end;
//still here so notation was correct and baseaddress+offsets are filled in
//now read
realaddress2:=baseaddress;
for i:=0 to length(offsets)-1 do
begin
check:=readprocessmemory(processhandle,pointer(realaddress2),@realaddress,4,count);
if check and (count=4) then
realaddress2:=realaddress+offsets[i]
else
exit;
end;
result:=realaddress2;
error:=false;
finally
list.free;
end;
end;
function TSymhandler.ParseAsPointer(s: string; list:tstrings): boolean;
var i: integer;
prolog: boolean;
currentlevel: integer;
temps: string;
ispointer: boolean;
begin
//parse the string
result:=false;
currentlevel:=0;
prolog:=true;
temps:='';
ispointer:=false;
for i:=1 to length(s) do
begin
if s[i]='[' then
begin
if prolog then
begin
inc(currentlevel);
ispointer:=true;
end
else
exit; //bracket open after the prolog is not allowed
end
else
begin
if prolog then
begin
if not (s[i] in [#8,' ']) then //no space or tab
prolog:=false;
end;
if not prolog then
begin
//definition, currentlevel is set, now parse till last ] (currentlevel=0)
if s[i]=']' then //end of a level
begin
dec(currentlevel);
if temps='' then temps:='+0';
list.Add(temps);
temps:='';
if currentlevel<0 then exit;
continue;
end
else
temps:=temps+s[i];
end;
end;
end;
if temps='' then temps:='+0';
if (ispointer) and (temps<>'') then list.Add(temps);
if currentlevel>0 then exit;
result:=ispointer;
end;
destructor TSymhandler.destroy;
begin
if symbolloaderthread<>nil then
begin
symbolloaderthread.Terminate;
symbolloaderthread.WaitFor;
symbolloaderthread.free;
end;
symbolloadervalid.Free;
modulelistMREW.free;
userdefinedsymbolsMREW.free;
setlength(userdefinedsymbols,0);
setlength(modulelist,0);
end;
constructor TSymhandler.create;
begin
symbolloadervalid:=TMultiReadExclusiveWriteSynchronizer.create;
modulelistMREW:=TMultiReadExclusiveWriteSynchronizer.create;
userdefinedsymbolsMREW:=TMultireadExclusiveWriteSynchronizer.create;
setlength(userdefinedsymbols,32);
setlength(modulelist,32);
showmodules:=false;
showsymbols:=true;
end;
initialization
symhandler:=tsymhandler.create;
selfsymhandler:=Tsymhandler.create;
selfsymhandler.targetself:=true;
finalization
selfsymhandler.free;
symhandler.free;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -