Dan-Levi Skrevet 7. mai 2016 Del Skrevet 7. mai 2016 Hei, Jeg har i lengere tid ønsket å lære meg hvordan man injiserer kode i en kjørende process og har i denne sammenheng startet et lite prosjekt. Prosjektet går ut på å injisere notepad med en dll som laster CLR og en managed dll for så å kjøre en metode skrevet i c# som skal manipulere notepad. Jeg har laget et prosjekt i Visual Studio 2015: WPF applikasjon. CppDLL.dll - Unmanaged dll (CLR og lasting av managed dll)SharpDLL.dll - Managed dll. dllmain.cpp (CppDLL.dll) #include "stdafx.h" #include <Windows.h> #include <metahost.h> #pragma comment(lib, "mscoree.lib") #import "mscorlib.tlb" raw_interfaces_only \ high_property_prefixes("_get","_put","_putref") \ rename("ReportEvent", "InteropServices_ReportEvent") void LoadDotNet() { HRESULT hr; ICLRMetaHost *pMetaHost = NULL; ICLRRuntimeInfo *pRuntimeInfo = NULL; ICLRRuntimeHost *pClrRuntimeHost = NULL; hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)); hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)); hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pClrRuntimeHost)); hr = pClrRuntimeHost->Start(); DWORD pReturnValue; hr = pClrRuntimeHost->ExecuteInDefaultAppDomain( L"C:\\Users\\DanHovedPC\\Desktop\\inject\\SharpDLL.dll", L"SharpDLL.Injected", L"Start", L"Hello from .NET", &pReturnValue); pMetaHost->Release(); pRuntimeInfo->Release(); pClrRuntimeHost->Release(); } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: MessageBox(NULL, L"Hi!", L"From cpp DLL", NULL); //LoadDotNet(); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } Injection.cs (SharpDLL.dll) using System.Windows; namespace SharpDLL { class Injected { public static int Start(string arg) { MessageBox.Show(arg); return 0; } } } CppDLL.net blir injisert, og som koden nå viser viser den en meldingsboks med "Hi" i. Når jeg prøver å kjøre LoadDotNet() funksjonen blir CLR lastet men det kommer ikke opp noen ny meldingsboks. dll'en feiler å kjøre metoden og jeg vet ikke hvor jeg skal starte å debugge. Noen som har peil? På forhånd takk for svar. Lenke til kommentar
ahw_ Skrevet 7. mai 2016 Del Skrevet 7. mai 2016 (endret) Hei! Har du sjekket verdien til hr underveis? Hvor feiler det? Se f.eks. denne oversikten. For å debugge DLL-fila som vanligvis injiseres, har du minst tre valg: Lag deg en enkel applikasjon som laster inn DLL-fila (statisk eller dynamisk). «Attach to» Notepad mens din meldingsboks vises. Loggføring. Anbefaler at du tester ting i små steg, og forsikrer deg om at ting fungerer før du tester i «stor skala». Endret 7. mai 2016 av ahw_ Lenke til kommentar
Dan-Levi Skrevet 7. mai 2016 Forfatter Del Skrevet 7. mai 2016 Hei takk for svar og tips! Jeg har funnet ut at hr returnerer korrekt ned til rett før pClrRuntimeHost->Start(); _com_error err(hr); LPCTSTR errMsg = err.ErrorMessage(); // The operation completed successfully Jeg er ikke helt dreven i c++, enda en av grunnene til dette prosjektet, så det er noen grunnleggende ting jeg ikke har lært enda, men jeg prøver å pakke inn de siste linkene i en try catch blokk og vise en meldingsboks men den vises ikke. try { hr = pClrRuntimeHost->Start(); pMetaHost->Release(); pRuntimeInfo->Release(); pClrRuntimeHost->Release(); } catch (const std::exception& e) { MessageBox(NULL,(LPCWSTR)e.what(),L"BAR",NULL); } Hva gjør jeg feil her? Lenke til kommentar
ahw_ Skrevet 7. mai 2016 Del Skrevet 7. mai 2016 Hei takk for svar og tips! Jeg har funnet ut at hr returnerer korrekt ned til rett før pClrRuntimeHost->Start();[snip]Hva gjør jeg feil her? Vet ikke om noen Windows API-er som bruker C++ exceptions. Du kan prøve å håndtere exceptions med SEH som er spesifikt for Windows med __try/__except. Lenke til kommentar
ahw_ Skrevet 7. mai 2016 Del Skrevet 7. mai 2016 (endret) Har ikke prøvd dette men kanskje det kan hjelpe litt: Mixing SEH and C++ Exceptions Hva er det egentlig pClrRuntimeHost->Start() returnerer? Endret 7. mai 2016 av ahw_ Lenke til kommentar
Dan-Levi Skrevet 7. mai 2016 Forfatter Del Skrevet 7. mai 2016 snip Vet ikke om noen Windows API-er som bruker C++ exceptions. Du kan prøve å håndtere exceptions med SEH som er spesifikt for Windows med __try/__except. Forsøkte å bruke __try __except men samme resultat. Har ikke prøvd dette men kanskje det kan hjelpe litt: Mixing SEH and C++ Exceptions Hva er det egentlig pClrRuntimeHost->Start() returnerer? Returnerer HRESULT etter hva jeg kan forstå HRESULT __stdcall ICLRRuntimeHost::Start() Sliter med forstå hvordan jeg kan gjøre errorhandling her.. Men liker utfordringer så gir meg ikke! Selv om jeg føler jeg har lest gjennom hele google snart, hehe Lenke til kommentar
ahw_ Skrevet 7. mai 2016 Del Skrevet 7. mai 2016 Returnerer HRESULT etter hva jeg kan forstå HRESULT __stdcall ICLRRuntimeHost::Start() Sliter med forstå hvordan jeg kan gjøre errorhandling her.. Men liker utfordringer så gir meg ikke! Selv om jeg føler jeg har lest gjennom hele google snart, hehe Mente verdien. Vanligvis gjør man noe som dette: if (FAILED(hr)) {} // eller if (SUCCEEDED(hr)) {} Er problemet ditt at ICLRRuntimeHost::Start aldri returnerer? Se her: http://stackoverflow.com/a/34743792 Lenke til kommentar
ahw_ Skrevet 7. mai 2016 Del Skrevet 7. mai 2016 Litt mer... Code within DllMain must not access the CLR. This means that DllMain should make no calls to managed functions, directly or indirectly; no managed code should be declared or implemented in DllMain; and no garbage collection or automatic library loading should take place within DllMain. https://msdn.microsoft.com/en-us/library/ms173266.aspx 1 Lenke til kommentar
Dan-Levi Skrevet 7. mai 2016 Forfatter Del Skrevet 7. mai 2016 (endret) Bingo! Kudos :-) Leser også at man skal være forsiktig med det meste i DllMain, men at det er greit at man bruker CreateThread? CreateThread is one of the few things you can do inside DllMain, because it's a call to kernel32 which is guaranteed to be already loaded. http://stackoverflow.com/questions/1688290/creating-a-thread-in-dllmain#comment-2166738 Akkurat nå hadde jeg et vellykket forsøk på å CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)LoadDotNet, NULL, 0, NULL); Endret 7. mai 2016 av Dan-Levi Lenke til kommentar
ahw_ Skrevet 7. mai 2016 Del Skrevet 7. mai 2016 (endret) Du kan bruke CreateThread så vidt jeg vet, så lenge du ikke blokkerer DllMain. Du kan med andre ord ikke vente på at tråden skal jobbe seg ferdig med f.eks. WaitForSingleObject, fordi tråden egentlig starter etter at DllMain returnerer. Har ikke lest så mye om akkurat dette. Det er synd hvis koden du injiserer må kjøre tidlig. Det kan kanskje være mulig å gå rundt problemet på et eller annet vis, men det blir kanskje ganske «hacky» i så fall. Endret 7. mai 2016 av ahw_ Lenke til kommentar
Dan-Levi Skrevet 7. mai 2016 Forfatter Del Skrevet 7. mai 2016 Okey. Vel, dette er et helt nytt emne å sette seg inn i men synes det er utrolig interessant å kunne ta kontroll over andre prosesser og manipulere dem. Poster tilbake når jeg har fått til noe morsomt. Lenke til kommentar
ahw_ Skrevet 9. mai 2016 Del Skrevet 9. mai 2016 (endret) Jeg har en bedre idé til deg enn å bruke CreateThread inni DllMain, som jeg personlig har testet ut for moro skyld. Det er en «enkel» løsning jeg har mekket sammen kjapt ut i fra egen kunnskap og biter med informasjon hentet fra her og der etter hvert som jeg fant problemer. Løsningen går ut på nesten det samme, men i stedet for å mate CreateRemoteThread med adressen til LoadLibraryW (som er det enkleste), injiserer du kode som først laster inn DLL-en og deretter kaller en eksportert funksjon. Fordelen er at koden din kjøres etter DllMain, når du kan gjøre hva enn du ønsker. Ulempen er at du må bygge opp denne koden med x86/x64 assembler-instruksjoner (et nyttig verktøy som hjalp meg: Online x86 / x64 Assembler and Disassembler) og passe på flere ting. Dette er mer avansert men det fungerer bedre. I det uferdige eksempelet jeg har utviklet skjer alt synkront: CreateProcess med CREATE_SUSPENDED. Injiserer koden som både laster inn DLL-en og kjører den eksporterte funksjonen. CLR lastes inn og kjører funksjonen i .NET-programmet. Venter til alt er ferdig. Hovedtråden i prosessen fortsetter. Hvis du ikke allerede har erfaring med x84/x64 assembly er selvsagt dette et nytt og stort emne, men det vil du få god bruk for uansett hvis du fortsetter med disse tingene – faktisk tror jeg det er litt vanskelig å unngå. Noen andre emner når man først er inne på dette, er debugging av tredjepartsprogrammer uten kildekoden (bare assembly), anti-debugging, anti-DLL-injection, osv. Du kan få til mye rart med dette. En personlig favoritt er knekking/ødelegging av kode. Endret 9. mai 2016 av ahw_ Lenke til kommentar
Dan-Levi Skrevet 17. mai 2016 Forfatter Del Skrevet 17. mai 2016 Spennende dette her! Bare å dele kodeeksempler om du måtte føle for det. God 17 mai! Lenke til kommentar
ahw_ Skrevet 17. mai 2016 Del Skrevet 17. mai 2016 (endret) Eksempelet mitt er litt rotete, mangler fleksibilitet, isolering av kode, feilsjekking osv.. Bør absolutt ikke brukes i produksjon. https://github.com/SteffenL/InjectDotNetAssemblyExample Du kan f.eks. bygge dette med følgende kommando med VS Developer Command Prompt: msbuild /t:Build /p:Configuration=Release /p:Platform=x64 Koden min støtter både x86 og x64, men pass på å ta en ren bygg hvis du bytter mellom disse.. Dette er litt klossete fordi jeg har blandet forskjellige prosjekttyper (managed/native). Et relatert tema er «hooking» av kode/funksjoner. Dette er ikke inkludert i eksempelet. Endret 17. mai 2016 av ahw_ Lenke til kommentar
ahw_ Skrevet 17. mai 2016 Del Skrevet 17. mai 2016 Har nå tatt en liten opprydding i koden. Har også fått på plass henting av feilmelding fra CLR, men har ikke testet at dette alltid fungerer. Det er fortsatt mer å gjøre, men tar meg en pause inntil videre. Lenke til kommentar
Dan-Levi Skrevet 18. mai 2016 Forfatter Del Skrevet 18. mai 2016 Skal se så fort jeg har tid, tittet så vidt på det her i går men var ikke nok tid. Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå