Gå til innhold
🎄🎅❄️God Jul og Godt Nyttår fra alle oss i Diskusjon.no ×

Noen som har peiling på dll injesering og lasting av CLR?


Anbefalte innlegg

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
Videoannonse
Annonse

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:

  1. Lag deg en enkel applikasjon som laster inn DLL-fila (statisk eller dynamisk).
  2. «Attach to» Notepad mens din meldingsboks vises.
  3. 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 av ahw_
Lenke til kommentar

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

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

 

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  :wee:

Lenke til kommentar

 

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  :wee:

 

 

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

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 av Dan-Levi
Lenke til kommentar

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 av ahw_
Lenke til kommentar

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:

  1. CreateProcess med CREATE_SUSPENDED.
  2. Injiserer koden som både laster inn DLL-en og kjører den eksporterte funksjonen.
  3. CLR lastes inn og kjører funksjonen i .NET-programmet.
  4. Venter til alt er ferdig.
  5. 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 av ahw_
Lenke til kommentar
  • 2 uker senere...

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 av ahw_
Lenke til kommentar

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

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 konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...