ich weiß ... 'n bissl spät, aber besser, als nie
In Windows werden die Specherblöcke immer nur in 64 KB-Blöcken reserviert, also alle $10000 Byte ein neuer Block und weil es nunmal bei 0 beginnt, liegen die unteren Bits innerhalb einens Blocks.
Mit
h := cardinal(addr) and $FFFF0000; wird also erstmal an den anfang des ersten Blocks gesprungen.
Tja, und dann geht es, in 'ner netten Schleife, Block für Block zurück:
Delphi-Quellcode:
repeat
dec(h, $10000);
until ... (h = 0);
Und das solange, bis man 'nen Modulnamen, also mehr als 0 Zeichen zurückgeliefert bekommt:
Delphi-Quellcode:
repeat
i := GetModuleFilename(h,buf,255);
until (i <> 0) ...;
Am Ende wird dann (wenn was gefunden wurde) wieder ein Block hinzugezählt, denn dieser wurde ja nach dem Auffinden (per GetModuleFilename) von diesem
DEC abgezogen (man ist dann also vor dem Modul, obwohl man ja die Adresse des Moduls wollte).
Delphi-Quellcode:
. i := GetModuleFilename(h,buf,255);
dec(h,$10000);
until (i <> 0)
or (h = 0);
if (h = 0)
then ..
else result := h+$10000;
Man könnte natürlich auch erstmal was zurechnen und die Abfrage umdrehen:
(da h am Ende eh dem Result zugewiesen wird, kann man auch gleich Result verwenden)
Delphi-Quellcode:
function GetRealModuleHandle(addr: pointer): cardinal;
stdcall;
var i: cardinal;
buf:
array[0..MAX_PATH-1]
of char;
begin
Result := (cardinal(addr) + $0000FFFF)
and $FFFF0000;
repeat
dec(Result, $10000);
i := GetModuleFilename(h, buf, MAX_PATH);
until (i <> 0)
or (Result = 0);
end;
Delphi-Quellcode:
function GetRealModuleHandle(addr: pointer): cardinal;
stdcall;
var buf:
array[0..MAX_PATH-1]
of char;
begin
Result := (cardinal(addr) + $0000FFFF)
and $FFFF0000;
repeat
dec(Result, $10000);
until (GetModuleFilename(h, buf, MAX_PATH) <> 0)
or (Result = 0);
end;
Schneller geht es, wenn man direkt anfragt, wo der Anfang ist und gleich noch prüft was da ist.
Delphi-Quellcode:
function GetRealModuleHandle(addr: pointer): cardinal;
var MBI: MEMORY_BASIC_INFORMATION;
begin
if (VirtualQuery(addr, MBI, SizeOf(MBI)) <> 0)
and (MBI.Type_9 = MEM_IMAGE) and (MBI.State = MEM_COMMIT) then
Result := cardinal(MBI.AllocationBase) else Result := 0;
end;
außerdem bekommt man so einen richtigen Wert, denn die Funktion von uallcollection sucht ja solange, bis sie was findet, aber ob dieses noch zum selben Speicherblock gehört is dem Teil egal.
Theoretisch könnte man den Pointer hinter einem Modul positionieren, also irgendwo (z.B. in einem nicht reserviertem Specherbereich, oder in irgendwas Anderem), halt nur nicht
in einem nicht Modul.
Und obwohl man dann 0 als ergebnis haben müßte (ohne Modul gibt's ja auch keine Adresse, wo es (was ja nicht da ist) beginnt ... aber so würde es jedes Modul finden, welche einfach nur vor dem Pointer beginnt.