Windows
Code Injection - Nachtrag 1 PDF Print E-mail

Code Injection - Nachtrag 1

In den letzten Tagen und Wochen habe ich weiter an meinen kleinen Tools gebastelt und sie so verändert, dass nur noch eine Anwendung benötigt wird.
Diese Konsolenanwendung beinhaltet auch die Dll selbst, welche mittels LoadLibrary in dem Remote Prozess geladen wird. 

Der Ablauf:

  • Konsolenanwendung startet
  • PID Eingabe
  • Dll wird im tmp Ordner erzugt ( versteckt in einer Text Datei mittels Alternate Data Stream )
  • Code Injection wird durchgeführt
  • Tmp Datei wird gelöscht
  • Programm beendet sich

Getestet habe ich das Programm unter folgenden Betriebssystemen und Virenscannern:

Betriebssystem Virenscanner
 Code Injection 
 Windows Vista - Ultimate 64 Bit
 Kaspersky Antivirus 8
    erfolgreich
 Windows XP - Professional 32 Bit
 Avira AntiVir Personal 9

    erfolgreich

Windows 7 - Home Premium 64 Bit
 McAfee 

    erfolgreich

Windows Server 2003 - 32 Bit
 ---   

    erfolgreich

 

Wer das Programm selber gerne mal testen möchte kann es hier downloaden:

http://wcqtff.willcodejoomlaforfood.de/botoxconsole.7z

Folgende Testpunkte sind interessant:

  • Erkennt der Virenscanner Schadcode in der botoxconsole.exe  ?
  • Wird die CodeInjection erfolgreich ausgeführt

Ob die Injection geklappt hat oder nicht, merkt man wenn man dem entsprechenden Programm den Focus verleiht
und die F1 Taste drückt. Nun sollten mehr oder weniger Messageboxen erscheinen.

Nach dem Neustart der Anwendung ist wieder alles beim alten.

Last Updated on Monday, 04 January 2010 15:11
 
Code Injection - VirtualAllocEx,WriteProcessMemory,CreateRemoteThread - Teil 1 von 3 PDF Print E-mail
User Rating: / 3
PoorBest 

Heute möchte ich den ersten Teil meiner Research Arbeit über Code Injection vorstellen. Es handelt sich um den Aufbau und die Idee dahinter.
Es gibt zwar schon fertige Lösungen und Frameworks auf diversen Seiten im Internet, aber ich wollte eine Möglichst einfache Klasse schreiben,
mit wenig Overhead und Assembler.

Die Idee:

Mittels der CreateRemoteThread Funktion ist es möglich einen Thread in einem anderen Prozess zu starten, diese Tatsache ansich fand ich schonmal sehr spannend.
Dies ist der übliche Weg wie Debugger arbeiten. Mein Ziel war es also ein kleines Programm zu schreiben welches einen Thread in einem anderen Prozess erstellt und
eine MessageBox mit der Pid darstellt. Ist dies erstmal geschafft, kann man noch mehr tolle Sachen im anderen Prozess veranstalten.

Der Aufbau:

Nach etlichen Versuchen und Ansätzen bin ich zu folgendem Aufbau gelangt. Meine Lösung besteht aus 2 Teilen. 

  • Ein Programm welches die Injection druchführt
  • Eine DLL die den entsprechenden Code ausführt

Vorteil, man kann die DLL beliebig austauschen und muss nicht sein eigentliches Programm anpassen.

Weiterführende Links:

Last Updated on Saturday, 05 December 2009 12:47
 
Code Injection - VirtualAllocEx,WriteProcessMemory,CreateRemoteThread - Teil 2 von 3 PDF Print E-mail

Nun im zweiten Teil möchte ich das eigentliche Programm vorstellen. Es handelt sich um eine Konsolenanwendung,
welche eine PID einliest. Danach wird versucht, diesem Prozess den Code zu injizieren. Wichtig dabei ist, das man über
entsprechende Rechte verfügt. Ganz konkret ist das Debug
Recht gemeint ( SE_PRIVILEGE_ENABLED ).

Mittles der Funktionen OpenProcessToken, LookupPrivilegeValue und AdjustTokenPrivileges ist es recht
einfach die Rechte eines Prozesses zu verändern.

Hier ein kleines Code Schnipsel:

OpenProcessToken( GetCurrentProcess(), 
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hAppToken )
LookupPrivilegeValue( NULL,
SE_DEBUG_NAME,
&debugLuid )

AdjustTokenPrivileges( hAppToken,
FALSE,
&tokenPrivileges,
sizeof( tokenPrivileges ),
NULL,
NULL )
Kommen wir nun zum wichtigsten Programmteil, die Erstellung des Threads in einem anderen Prozess.
Wie beschrieben sollte zuerst geprüft werden ob Debugrechte vorhanden sind, bzw ob diese erlangt werden können.
Danach öffnet man mittles der OpenProcess API den entsprechenden Prozess.

Nun wird mittels der Funktion VirtualAllocEx Arbeitsspeicher im entsprechenden Prozess allokiert. Danach müssen noch die
eigentlichen Daten in diesen Speicher geschrieben werden, dies übernimmt WriteProcessMemory.
War auch das schreiben erfolgreich, wird nun die eigentliche Funktion zum erstellen eines Threads aufgerfuen.
Die CreateRemoteThread Funktion, bei Erfolg erhält man ein HANDLE auf den Thread im anderen Prozess.

Nun schauen wir uns die 3 Schritte im Detail an:

VirtualAllocEx:

 const std::string dll = "botox.dll"; 

VirtualAllocEx( hRemoteProcessHandle,
                     NULL,
                     dll.length(),
                     MEM_RESERVE|MEM_COMMIT,
                     PAGE_EXECUTE_READWRITE )

Wir übergeben das Prozess HANDLE, die Länge des DLL Names ( Anzahl der zu reservierenden Bytes , danach noch die entsprechenden
Flags das der Speicher auch ausführbaren Code enthält.
Wir erhalten einen void Pointer als Antwort.

WriteProcessMemory:

Nach dem erfolgreichen reservieren von Arbeitsspeicher müssen wir nun noch die Daten in diesen schreiben. In diesem Fall der Name der Dll,
welche vom Prozess geladen werden soll.

 WriteProcessMemory( hRemoteProcessHandle, 
                                reinterpret_cast<LPVOID>( pRemoteMemory ),
                                dll.c_str(),
                                dll.length(),
                                NULL )

Wieder wird das Prozess HANDLE übergeben, sowie den Pointer der auf den zuvor allokierten Arbeitsspeicher zeigt. Danach die eigentlichen
Daten, mit Längeangabe.

CreateRemoteThread:

Nun die eigentliche Erstellung mittels CreateRemoteThread:

reinterpret_cast<LPVOID>( GetProcAddress( GetModuleHandle( L"kernel32.dll" ), "LoadLibraryA" ) ); 
CreateRemoteThread( hRemoteProcessHandle, 
                                NULL,
                                NULL,
                                reinterpret_cast<LPTHREAD_START_ROUTINE>(pLoadLibrary),
                                reinterpret_cast<LPVOID>(pRemoteMemory),
                                NULL,
                                NULL );

Auch hier zuerst das Prozess HANDLE, danach einen Pointer auf eine ThreadProc in diesem Fall die LoadLibrary Funktion der kernel32.dll.
Danach den Arbeitsspeicher, fertig. Zurück bekommt man ein HANDLE auf den Thread.

Bei meinen Recherchen, hatten viele Leute Probleme mit dieser Lösung unter Windows Vista. Dies kann ich aber nicht bestätigen,
mein Programm wurde unter
Windows Vista 64 bit entwickelt und getestet. Bei allen Versuchen war die Adresse von LoadLibraryA in der kernel32.dll konstant gleich.

Weiterführende Links:

 

Last Updated on Saturday, 05 December 2009 12:43
 
Code Injection - VirtualAllocEx,WriteProcessMemory,CreateRemoteThread - Teil 3 von 3 PDF Print E-mail

Den dritten un letzten Teil widme ich der DLL, welche den auszuführenden Code beinhaltet. Dieser Teil ist recht einfach zu
implementieren. Im Grunde wird bei LoadLibrary einfach ein weiteren Thread gestartet, welcher dann die Arbeit übernimmt.

Der Einstiegspunkt - LoadLibrary:

Wird die Dll von einem Prozess geladen wird einfach ein weiteren Thread gestartet.

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpvReserved */)
{
   if (dwReason == DLL_PROCESS_ATTACH )
   {
        DoAction();
   }

   return TRUE;
}

Die DoAction Funktion erzeugt einen neuen Thread, welcher über alle Fenster mittels EnumWindows iteriert.

 void DoAction()
{
    CreateThread( NULL,
                  0,
                  ThreadProc,
                  0,
                  0,
                  0);    
}

DWORD WINAPI ThreadProc(  LPVOID lpParameter )
{

   EnumWindows( EnumWindowsProc, 0 );
 
   while( 1 )
   {
       Sleep( 100 );
   }

    return 0;
}

BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam )
{
    const DWORD currentID = GetCurrentProcessId();
    DWORD procid = 0;
    GetWindowThreadProcessId (hwnd, &procid);

    if( currentID == procid )
    {
        SetWindowsHookEx( WH_KEYBOARD, KeyboardProc, NULL,  );
    }
    return TRUE;
}

LRESULT CALLBACK KeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
{

   // implementation

}

Weiterführende Links:

Last Updated on Monday, 14 December 2009 21:00
 
Terminal Server Session Monitoring PDF Print E-mail
User Rating: / 2
PoorBest 

Hier möchte ich nun ein selbstgeschriebenes Tool names who vorstellen. Der Name orientiert sich an dem gleichnamigen Linux Tool.

Who ist eine kleine Konsolenanwendung, welche alle Windows Sessions auflistet und im Sekundentakt aktualisiert. Benutzt wird dabei folgende WTS* API:

  • WTSQuerySessionInformation
  • WTSEnumerateSessions
  • WTSGetActiveConsoleSessionId
  • WTSFreeMemory

Zu finden ist es in folgendem Repository: svn://willcodejoomlaforfood.de/tools/trunk/windows/who

 

Last Updated on Wednesday, 18 November 2009 21:09
 
Windows Socket Problem: warning C4005: 'AF_IPX': Makro-Neudefinition PDF Print E-mail
User Rating: / 4
PoorBest 

Hier möchte ich kurz eine Lösung vorstellen, für alle die Probleme mit dem Kompilieren der Windows Socket API ( winsock2.h ) haben.

Das Problem ergibt sich durch macro redifintions:

1>\windows\v6.1\include\ws2def.h(91) : warning C4005: 'AF_IPX': Makro-Neudefinition
\windows\v6.1\include\winsock.h(460): Siehe vorherige Definition von 'AF_IPX'
\windows\v6.1\include\ws2def.h(127) : warning C4005: 'AF_MAX': Makro-Neudefinition
\windows\v6.1\include\winsock.h(479): Siehe vorherige Definition von 'AF_MAX'
\windows\v6.1\include\winsock.h(402): Siehe vorherige Definition von 'SO_DONTLINGER'
\windows\v6.1\include\ws2def.h(207) : error C2011: 'sockaddr': 'struct' Typneudefinition
\windows\v6.1\include\winsock.h(485): Siehe Deklaration von 'sockaddr'
\windows\v6.1\include\ws2def.h(385) : error C2143: Syntaxfehler: Es fehlt '}' vor 'Konstante'
\windows\v6.1\include\ws2def.h(385) : error C2143: Syntaxfehler: Es fehlt ';' vor 'Konstante'
\windows\v6.1\include\ws2def.h(385) : error C2059: Syntaxfehler: 'Konstante'
\windows\v6.1\include\ws2def.h(438) : error C2143: Syntaxfehler: Es fehlt ';' vor '}'
\windows\v6.1\include\ws2def.h(519) : warning C4005: 'IN_CLASSA': Makro-Neudefinition
\windows\v6.1\include\winsock.h(287): Siehe vorherige Definition von 'IN_CLASSA'
\windows\v6.1\include\ws2def.h(525) : warning C4005: 'IN_CLASSB': Makro-Neudefinition
\windows\v6.1\include\winsock.h(293): Siehe vorherige Definition von 'IN_CLASSB'
\windows\v6.1\include\ws2def.h(531) : warning C4005: 'IN_CLASSC': Makro-Neudefinition
\windows\v6.1\include\winsock.h(299): Siehe vorherige Definition von 'IN_CLASSC'
\windows\v6.1\include\ws2def.h(542) : warning C4005: 'INADDR_ANY': Makro-Neudefinition
\windows\v6.1\include\winsock.h(304): Siehe vorherige Definition von 'INADDR_ANY'
\windows\v6.1\include\ws2def.h(578) : error C2011: 'sockaddr_in': 'struct' Typneudefinition
\windows\v6.1\include\winsock.h(312): Siehe Deklaration von 'sockaddr_in'
\windows\v6.1\include\winsock2.h(132) : error C2011: 'fd_set': 'struct' Typneudefinition
\windows\v6.1\include\winsock.h(68): Siehe Deklaration von 'fd_set'
\windows\v6.1\include\winsock2.h(167) : warning C4005: 'FD_SET': Makro-Neudefinition

Das Problem ist die Include Reihenfolge der Windows Header Dateien. Eigentlich ist man gewöhnt zuerst die <windows.h> zu includieren, danach alles andere.
Leider ist die winsock2.h eine Ausnahme, diese muss vor der windows.h includier werden.

Weiterführende Links:

Last Updated on Wednesday, 14 October 2009 19:45