Microsofts Detours Library 2.1 mit BCB?
-
So, muss den Thread nochmal hochholen.
Also die Lib, die DLL sowie das Tracetcp Beispiel kann ich kompilieren.
Wenn ich jetzt aber mit Withdll die DLL z.B. in Fireforx lade passiert nichts. Die Beispiel DLL ist mehr oder weniger "Standard", d.h. ich habe daran keine änderungen vorgenommen (Beep() mal aussen vorgelassen).
Wenn ich die DLL nehme dich ich mit Vc++ 2008 kompiliert habe funktioniert es.
Es funktioniert auch wenn ich "meine" Detoured.dll" mit der von VC++ austausche. (meine, wenn ich meine mit BCB übersetzte detoured.dll mit der im VC++ Bin Verzeichnis austausche, d.h. ich überschreibe die VC DLL mit meiner BCB DLL).Firefox wird via "withdll" geladen. Setdll hab ich noch nicht ausprobiert, gehe aber davon aus das es damit auch nicht funktionieren wird!
Es sieht so aus als wäre doch noch irgendwo der Hund begraben, fraglich ist wo:
Die Projekt Files sehen so aus (Inhaltsmässig):
Detoured.dll:
- _detoured.cpp
- _detoured.h (beide umbenannt weil ich das DLL Projekt genauso genannt habe)Detours.lib
- _detoured.h
- _detours.cpp
- creatwth.cpp
- disasm.cpp
- image.cpp
- modules.cpptracetcp.dll
- _detoured.cpp
- _detoured.h
- _detours.cpp
- detours.h
- syelog.cpp
- syelog.h
- detours.lib
- detoured.libÄnderungen an den Dateien hab ich nicht vorgenommen, abgesehen von dem NullExport in der tracetcp.cpp sowie den Export in der (_)detoured.h für den Export von Detoured().
Den Nullexport für tracetcp habe ich so gemacht:
extern "C" __declspec (dllexport) __stdcall void NullExport();Die DLL ansich exportiert nur den NullExport sowie den CPP Debug Hook.
Irgendwas hab ich noch falsch gemacht, aber was
-
Maverick schrieb:
Irgendwas hab ich noch falsch gemacht, aber was
Eine Vermutung hätte ich da; bei meinen Versuchen trat ein Problem auf, dessen nicht eben naheliegende Lösung mit einem Unterschied zwischen BCC und MSVC in der Behandlung der statischen Referenzierung von DLL-Importen zusammenhing.
Im Beispiel "simple" in simple.cpp wird das Detouring folgendermaßen durchgeführt:
VOID (WINAPI * TrueSleep) (DWORD dwMilliseconds) = Sleep; VOID WINAPI TimedSleep(DWORD dwMilliseconds) { DWORD dwBeg = GetTickCount(); TrueSleep(dwMilliseconds); DWORD dwEnd = GetTickCount(); InterlockedExchangeAdd(&dwSlept, dwEnd - dwBeg); } BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) { LONG error; (void)hinst; (void)reserved; if (dwReason == DLL_PROCESS_ATTACH) { printf("simple.dll: Starting.\n"); fflush(stdout); DetourRestoreAfterWith(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)TrueSleep, TimedSleep); error = DetourTransactionCommit(); ...
Zunächst wird also die globale Variable TrueSleep mit dem WinAPI-Import Sleep initialisiert (Z. 1), dann später an DetourAttach() übergeben (Z. 26). Was trivial klingt, ist die Ursache unseres Problems; um das nachvollziehen zu können, ist es nötig zu wissen, wie DLL-Importe funktionieren.
Der Linker erstellt für alle Funktionen, die als __declspec (dllimport) markiert sind, eine Tabelle von Minimal-Stubs, die lediglich aus einer JMP-Anweisung mit einer Dummy-Adresse bestehen - eine Sprungtabelle. Der PE-Loader trägt, wenn das Modul geladen wird, in dieser Tabelle die tatsächlichen Adressen der Funktionen ein. Durch diesen Umweg wird dem Loader einiges an Arbeit erspart (unabhängig davon, wie oft eine importierte Funktion referenziert wurde, muß der Loader ihre tatsächliche Adresse nur einmal in der Sprungtabelle eintragen).
Dies läßt sich sehr einfach im Disassembler (Strg+Alt+C) nachvollziehen. Wenn du probehalber den folgenden Code in simple.cpp einfügst:Sleep (0);
, dann resultiert er in diesem Assembler-Code:
simple.cpp.40: Sleep (0); 003712A0 6A00 push $00 003712A2 E8B51B0000 call $00372e5c
Folgst du der CALL-Anweisung mit F7 (Einzelne Anweisung), so landest du in der Sprungtabelle:
... 00372E50 FF2510713700 jmp dword ptr [$00377110] 00372E56 FF2514713700 jmp dword ptr [$00377114] 00372E5C FF2518713700 jmp dword ptr [$00377118] ; <-- hier 00372E62 FF251C713700 jmp dword ptr [$0037711c] 00372E68 FF2520713700 jmp dword ptr [$00377120] ...
Folgst du auch der JMP-Anweisung mit F7, bist du am Ziel:
kernel32.Sleep: 7C802442 8BFF mov edi,edi 7C802444 55 push ebp 7C802445 8BEC mov ebp,esp 7C802447 6A00 push $00 7C802449 FF7508 push dword ptr [ebp+$08] 7C80244C E84BFFFFFF call $7c80239c 7C802451 5D pop ebp 7C802452 C20400 ret $0004 7C802455 90 nop 7C802456 90 nop 7C802457 90 nop 7C802458 FFFF db $ff $ff 7C80245A FFFF db $ff $ff 7C80245C 0000 add [eax],al 7C80245E 0000 add [eax],al 7C802460 322480 xor ah,[eax+eax*4] 7C802463 7C90 jl $7c8023f5 7C802465 90 nop
Der BCC behandelt statische Referenzierungen importierter Funktionen so wie einen gewöhnlichen Funktionsaufruf. Deshalb bewirkt diese Anweisung
VOID (WINAPI * TrueSleep) (DWORD dwMilliseconds) = Sleep;
, daß in TrueSleep die Adresse der Stub-Funktion in der Sprungtabelle eingetragen wird. Hier - allerdings ist das nur eine auf der Tatsache, daß die mitgelieferten Beispiele dort funktionieren, basierende, nicht verifizierte Vermutung - verhält sich MSVC anders: nämlich wird dort entweder vom PE-Loader oder vom Startup-Code der Anwendung in TrueSleep die tatsächliche Adresse der importierten Funktion eingetragen.
Dies hat nun aber zur Folge, daß du, wenn du DetoursAttach() mit TrueSleep aufrufst, die Adresse des Sprungtabellen-Stubs übergibst. Demnach sieht die Sprungtabelle nach dem Aufruf der Detours-Funktionen so aus:
... 00372E50 FF2510713700 jmp dword ptr [$00377110] 00372E56 FF2514713700 jmp dword ptr [$00377114] 00372E5C E9E3E3FFFF jmp TimedSleep(unsigned long) 00372E61 CC int 3 00372E62 FF251C713700 jmp dword ptr [$0037711c] 00372E68 FF2520713700 jmp dword ptr [$00377120] ...
Detours hat wunschgemäß die Funktion, auf die der übergebene Funktionszeiger verwies, umgelegt - den Stub in der Sprungtabelle. Jeder weitere Aufruf von Sleep() aus dem Modul, in dem die Detours-Funktionen aufgerufen wurden, erfolgt über diese Sprungtabelle und endet daher auch wie erwartet in TimedSleep(). Jedoch hat jedes Modul natürlich seine eigene Sprungtabelle, und die Sprungtabelle von sleep5.exe bleibt von obiger Aktion natürlich völlig unberührt und verweist nach wie vor auf die tatsächliche WinAPI-Funktion Sleep in kernel32.dll.
Das Problem kannst du lösen, indem du die TrueSleep zur Laufzeit zuweist:
typedef VOID (WINAPI * Sleep_t) (DWORD dwMilliseconds); Sleep_t TrueSleep; VOID WINAPI TimedSleep(DWORD dwMilliseconds) { ... } BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) { LONG error; (void)hinst; (void)reserved; if (dwReason == DLL_PROCESS_ATTACH) { printf("simple.dll: Starting.\n"); fflush(stdout); DetourRestoreAfterWith(); TrueSleep = reinterpret_cast <Sleep_t> (GetProcAddress (GetModuleHandle (TEXT ("kernel32.dll")), "Sleep")); // <-- DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)TrueSleep, TimedSleep); error = DetourTransactionCommit();
Danach verweist TrueSleep auf die tatsächliche Adresse der Funktion, und entsprechend verändert DetourAttach() auch die WinAPI-Funktion selbst (natürlich nur für den aktuellen Prozeß):
kernel32.Sleep: 7C802442 E9FDEDB683 jmp TimedSleep(unsigned long) 7C802447 6A00 push $00 7C802449 FF7508 push dword ptr [ebp+$08] 7C80244C E84BFFFFFF call $7c80239c 7C802451 5D pop ebp 7C802452 C20400 ret $0004 7C802455 90 nop ...
-
Danke für die ausführliche Erklärung. Werde das heute abend dann mal versuchen
-
vorab, hut ab, klasse thread und klasse inhalt.
nur ich komm nicht weiter.hab beide statische libs detoured (16kb), detours (269kb) erstellt.
danach ein projekt angefangen, worin ich ws32.send detouren will.habs nach deinem verfahren gemacht @audacia.
True_Send = reinterpret_cast <PSEND> (GetProcAddress(GetModuleHandle("Ws2_32.dll"),"send"));
in True_Send steht die addy von w32.send aber die detour libs wollen partout
kein jmp erstellen.woran kann es jetzt liegen Oo?
hab ich die libs falsch kompeliert?
schafft vielleicht einer von euch ws32.send zu detouren?wäre cool, wenner mir da irgendwie weiterhelfen könntet.
Greetz
-
retn schrieb:
True_Send = reinterpret_cast <PSEND> (GetProcAddress(GetModuleHandle("Ws2_32.dll"),"send"));
in True_Send steht die addy von w32.send aber die detour libs wollen partout
kein jmp erstellen.Zunächst setzt die Verwendung von GetModuleHandle() natürlich voraus, daß das fragliche Modul bereits mit LoadLibrary() oder als statischer Import vom PE-Loader in den Prozeß geladen wurde. Weiterhin geben DetourAttach(), DetourAttachEx() und DetourTransactionCommit() einen Fehlercode zurück, der bei der Diagnose evtl. hilfreich ist. Und den Typen PSEND brauchst du auch nicht selbst zu deklarieren.
Folgendes funktioniert einwandfrei bei mir:
#define INCL_WINSOCK_API_TYPEDEFS 1 #include <winsock2.h> #include <detours.h> WINSOCK_API_LINKAGE int WSAAPI replacement_send (SOCKET s, const char FAR * buf, int len, int flags) { } LPFN_SEND true_send; ... LoadLibrary (TEXT ("ws2_32.dll")); true_send = reinterpret_cast <LPFN_SEND> (GetProcAddress ( GetModuleHandle (TEXT ("ws2_32.dll")), "send")); DetourTransactionBegin (); DetourAttach (&(PVOID&) true_send, replacement_send); DetourTransactionCommit ();
-
In True_Send stand ja die richtige Addy, von daher muss es geladen sein, habs ja nachgeguckt.
Stimmt, an den Error code hab ich net gedacht und da ich den nun kenne, deprimiert es mich noch mehr xP.
Fehlercode: (8) ERROR_NOT_ENOUGH_MEMORY kam bei rum. Und wenn ich mir die detours.cpp anschaue, gibts 3 möglichkeiten, die relevant wären.
Irgendeine Idee?
Soviel Aufwand fürn kleinen Detour. ^^
-
retn schrieb:
Irgendeine Idee?
Eine Debug-Version von detours.lib erstellen und mal durchsteppen?
-
geht net klar
hab mich auf die detour lib gefreut wien fuchs... und nu
nunja mal sehen, dtrotzdem thanks
-
re
also ich hab mal wieder ka.
in vc08 hab ich die detours ohne probs hinbekommen. jetzt zu borland.
bin noch der überzeugung, dass ich die libs, dlls net richtig erzeuge, bzw. falsch oder garnet einbinde.also ich erstelle eine statische lib mit folgenden dateien:
creatwth.cpp
detours.cpp
image.cpp
disasm.cpp
modules.cppdanach erstelle ich eine dll mit:
detoured.cpp
detoured.hmit extern "C" __declspec( dllexport ) HMODULE WINAPI Detoured();
ein und kompeliere.k. klappt soweit.
um detours zu verwenden, adde ich zu meinem dll projekt die statische lib.
dann kommt folgendes
[Linker Error] Error: Unresolved external 'Detoured' referenced from C:\DETOUR_BCB\DETOURS.LIB|detoursso, wie verbinde ich jetzt die detoured.dll mit meiner dll und der statischen lib "detours"?
hoffe, ihr guckt noch in den thread.
greetz
-
retn schrieb:
um detours zu verwenden, adde ich zu meinem dll projekt die statische lib.
dann kommt folgendes
[Linker Error] Error: Unresolved external 'Detoured' referenced from C:\DETOUR_BCB\DETOURS.LIB|detoursDann füge doch die Importbibliothek für detoured.dll auch hinzu
-
will net ^^ ahhhh
kannst du mir vll. die komplette lib,dll an wakkaelpaso@gmx.net schicken?
greetz
-
@retn: Steht doch schon da wie du die DLL/LIB erzeugen musst.
Ich hab mir das andere "Problem" noch nicht angesehen, bin noch nicht dazu gekommen.
-
egal wie ich die kompeliere, es taucht immerwieder ein internes problem auf. wenns bei euch klappt, machts doch net nen umstand kurz zu schicken oder? ^^
-
retn schrieb:
es taucht immerwieder ein internes problem auf.
Wenn du das etwas genauer spezifizieren könntest, könnte man dir vielleicht auch helfen.
retn schrieb:
wenns bei euch klappt, machts doch net nen umstand kurz zu schicken oder? ^^
Doch. Meines Wissens untersagt Microsoft die Weitergabe der Detours-Quelldateien.
-
retn schrieb:
Fehlercode: (8) ERROR_NOT_ENOUGH_MEMORY kam bei rum. Und wenn ich mir die detours.cpp anschaue, gibts 3 möglichkeiten, die relevant wären.
Hatte ja schon eräwhnt, was für ein Fehler kommt, wenn ich sie mal richtig kompeliere. Da aber ihr nicht so ein Problem habt, kann es ja nur sein, dass ich immernoch was falsch mache.
Eine Sache die mir auffiel ist, dass wenn ich die Libs mitkompeliere und ein Detour starte, dass er sich nicht an die DETOURED.DLL heftet, so wie in der Visual C++ Version.
Ansonsten wäre es genial, wenn einer von euch hier ein komplettes Tutorial für den Erstellungsvorgang für Borland macht. Das alles ist doch etwas sehr zerstreut auf der Seite.
greetz
-
retn schrieb:
retn schrieb:
Fehlercode: (8) ERROR_NOT_ENOUGH_MEMORY kam bei rum. Und wenn ich mir die detours.cpp anschaue, gibts 3 möglichkeiten, die relevant wären.
Hatte ja schon eräwhnt, was für ein Fehler kommt, wenn ich sie mal richtig kompeliere. Da aber ihr nicht so ein Problem habt, kann es ja nur sein, dass ich immernoch was falsch mache.
Ah, du meinst immer noch den Laufzeitfehler. Bei deinem Post dachte ich zunächst, der Fehler träte beim Kompilieren auf.
retn schrieb:
Eine Sache die mir auffiel ist, dass wenn ich die Libs mitkompeliere und ein Detour starte, dass er sich nicht an die DETOURED.DLL heftet, so wie in der Visual C++ Version.
Das verwundert mich; eigentlich müßte das gleichermaßen der Fall sein.
Hast du mal ein Debug-Build erstellt? Was passiert in DetourAttachEx() an den Stellen, wo Detoured() explizit aufgerufen wird?retn schrieb:
Ansonsten wäre es genial, wenn einer von euch hier ein komplettes Tutorial für den Erstellungsvorgang für Borland macht. Das alles ist doch etwas sehr zerstreut auf der Seite.
Das werde ich bei Gelegenheit mal angehen.
-
ist noch jemand da, der sich mit dem thema beschäftigt?
greetz
-
Sorry für Doppelpost. :).
Hab folgendes Problem...
Vorab Infos:
Hab folgende Libs/DLLs erzeugt.Eine statische lib mit folgenden Dateien:
creatwth.cpp
detours.cpp
image.cpp
disasm.cpp
modules.cppEine detoured.dll:
detoured.cpp
detoured.hmit extern "C" __declspec( dllexport ) HMODULE WINAPI Detoured();
Alles klar soweit.
Dann habe ich meine eigentliche DLL erstellt, dazu die detours.lib, detoured.lib sowie headers
hinzugefügt.Kompeliere das Fehlerfrei. Folgender Code ist bis jetzt dabei:
case DLL_PROCESS_ATTACH: if (DetourRestoreAfterWith()==ERROR_INVALID_OPERATION) MessageBox(0,"fu","restore",0); sprintf(buf, "Error: %d, GetLastError: %d", error, GetLastError()); MessageBox(0,buf,"Info",0); True_Send = reinterpret_cast <PSEND> (GetProcAddress (GetModuleHandle (TEXT ("ws2_32.dll")), "send")); True_Recv = reinterpret_cast <PRECV> (GetProcAddress (GetModuleHandle (TEXT ("ws2_32.dll")), "recv")); DetourTransactionBegin(); if (!DetourUpdateThread(GetCurrentThread())) MessageBox(0,"fu","update",0); if (DetourAttach(&(PVOID&)True_Send, MySend) !=NO_ERROR) MessageBox(0,"fu","attach",0); //DetourAttach(&(PVOID&)True_Recv, MyRecv); if ( (error = DetourTransactionCommit()) != NO_ERROR) MessageBox(0,"fu","commit",0); sprintf(buf, "Error: %d, SendAddr: %x", error, True_Send); MessageBox(0,buf,"Info",0); break;
Das witzige dabei ist, dass ich jetzt für jeden Funktionsaufruf eine Messagebox bekomme, ergo Fehler. Hab direkt LastGetError nach dem ersten Funktionsaufruf von DetourRestoreAfterWith aufgerufen und was kam? Fehlercode: 126... ergo stimmt da was gewaltig net.
Der Fehlercode besagt, dass er gewisse ModuleHandles net findet. Na toll, ich kann damit wenig anfangen, leider -.-
greetz
-
Versuche mal, nicht die vom C++Builder übersetzte detoured.dll, sondern die als Binary beigelegte Version mithilfe von IMPLIB einzubinden.
-
Heyho,
hab über "implib detoured.lib detoured.dll" die importlib erstellt.
meinem projekt hinzugefügt, er linkt jetzt auf die von ms erstellte dll.
aber dennoch bleiben die fehler.greetz