Beispielprogramm zu Codeinjection

So, nach einer kleinen Pause wegen Studium und Zeit für die Tutorials hab ich mich nun nochmal dem Thema gewidmet. Ich denke mal, dass das Problem mit den Addressen nun behoben sein sollte. Meine Daten werden jetzt in eine struct geschrieben, welche vor dem Code in den Speicher geschrieben wird.
Code:
struct INJECTPARAMETER
{
    MESSAGEBOXA msgBoxA;
    LOADLIBRARYA loadlibraryA;
    EXITPROCESS exitprocess;
    char cCaption[15];
    char cText[15];
    char cDll[11];
};
Ich hab zum Test mal ein zweites Programm geschrieben, welches mir die Addresse von MessageBoxA (via GetProcAddress) ausgibt, und dieselbe Addresse befindet sich in msgBoxA. Calls zu hardgecodeten Addressen sind nun auch nicht mehr vorhanden.

Beim Aufruf von CreateRemoteThread hab ich mich da an den Weg aus der wiki gehalten. Meiner injectedThread Funktion wird die Addresse der struct mit übergeben.

So, ich hab dann mal versucht, den Code erstmal in meinem eigenem Process auszuführen, da aber VirtualAllocEx nun wieder den Fehler 487 zurückliefert, ist wohl nun der Punkt erreicht, um sich um das SeDebugPrivilege zu kümmern.
Code:
bool enableSeDebugPrivilege()
{
    HANDLE myProcess = GetCurrentProcess();
    TOKEN_PRIVILEGES pri;
    LUID luid;

    if(LookupPrivilegeValue(0, "seDebugPrivilege", &luid) == 0)
    {
        cout << "SE_PRIV: LookupPrivilegeValue: " << GetLastError() << endl;
        return false;
    }

    pri.PrivilegeCount = 0;
    pri.Privileges[0].Luid = luid;
    pri.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if(AdjustTokenPrivileges(myProcess, false, &pri, sizeof(TOKEN_PRIVILEGES), 0, 0) == 0)
    {
        cout << "SE_PRIV: AdjustTokenPrivileges: " << GetLastError() << endl;
        return false;
    }

    cout << "SeDebugPrivilege erfolgreich erhalten." << endl;

    CloseHandle(myProcess);

    return true;
}
Diese Funktion liefert mir jedoch bei AdjustTokenPrivileges() den Fehlercode 6 (ERROR_INVALID_HANDLE).
Frage: Was muss ich machen, um das Privileg zu ändern? Immerhin hab ich doch das richtige Handle mit GetCurrentProcess() erhalten.

Zum Schluss nun die Aktuelle version des Codes:
Code:
#include <iostream>
#include <windows.h>

using namespace std;

typedef HMODULE (WINAPI *LOADLIBRARYA)(LPCTSTR);
typedef int (WINAPI *MESSAGEBOXA)(HWND, LPCTSTR, LPCTSTR, UINT);
typedef void (WINAPI *EXITPROCESS)(UINT);

struct INJECTPARAMETER
{
    MESSAGEBOXA msgBoxA;
    LOADLIBRARYA loadlibraryA;
    EXITPROCESS exitprocess;
    char cCaption[15];
    char cText[15];
    char cDll[11];
};

void injectedThread(INJECTPARAMETER *p);
void injectedThread_end();
bool enableSeDebugPrivilege();

int main()
{
    HANDLE process;

    INJECTPARAMETER injParameter;
    strcpy(injParameter.cCaption, "Caption");
    strcpy(injParameter.cText, "Hallo Welt");
    strcpy(injParameter.cDll, "user32.dll");
    injParameter.loadlibraryA = (LOADLIBRARYA)GetProcAddress(LoadLibrary("kernel32.dll"), "LoadLibraryA");
    injParameter.msgBoxA = (MESSAGEBOXA)GetProcAddress(LoadLibrary("user32.dll"), "MessageBoxA");
    injParameter.exitprocess = (EXITPROCESS)GetProcAddress(LoadLibrary("kernel32.dll"), "ExitProcess");

    //Wie groß ist die Funktion injectedThread?
    DWORD InjThreadSize = reinterpret_cast<intptr_t>(&injectedThread_end) - reinterpret_cast<intptr_t>(&injectedThread);
    cout << "Differenz: " << InjThreadSize << endl;

    STARTUPINFO         startupInfo;
    PROCESS_INFORMATION processInfo;

    ZeroMemory(&startupInfo, sizeof(startupInfo));
    ZeroMemory(&processInfo, sizeof(processInfo));

    /*char szExe[] = "D:\\OllyDbg 2.0\\ollydbg.exe";
    if(CreateProcess((LPCTSTR)szExe, 0, 0, 0, false, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, 0, 0, &startupInfo, &processInfo) != 0)
    {
        cout << "CreateProcess war erfolgreich" << endl;
    }
    else
    {
        cout << "CreateProcess war nicht erfolgreich: " << GetLastError() << endl;
        return 0;
    }

    process = processInfo.hProcess;*/
    process = GetCurrentProcess();
    if(process == 0)
        cout << "Process konnte nicht geoeffnet werden" << endl;
    else
        cout << "Process geoeffnet" << endl;

    if(enableSeDebugPrivilege() != true)
    {
        cout << "SeDebugPrivilege nicht erhalten" << endl;
        return 0;
    }

    //nach beschreibbarn speicher suchen
    _SYSTEM_INFO info;
    GetSystemInfo(&info);
    cout << "MinimumApplicationAddress: " << info.lpMinimumApplicationAddress << endl;
    cout << "MaximumApplicationAddress: " << info.lpMaximumApplicationAddress << endl;

    _MEMORY_BASIC_INFORMATION memInfo;
    LPVOID actualAddr = info.lpMinimumApplicationAddress;

    while(actualAddr < info.lpMaximumApplicationAddress)
    {
        VirtualQueryEx(process, (LPCVOID)actualAddr, &memInfo, sizeof(memInfo));
        if(memInfo.State == MEM_FREE)
            break;
        else
        {
            SIZE_T act = (SIZE_T)actualAddr;
            act += memInfo.RegionSize;
            actualAddr = (LPVOID)act;
        }
    }

    cout << "Freien Speicher an der Speicherstelle " << actualAddr << " mit der size " << memInfo.RegionSize << " gefunden" << endl;
    DWORD dwSize = memInfo.RegionSize -10;
    if(dwSize < InjThreadSize)
        cout << "WARNUNG: nich genügend speicher mit MEM_FREE!!!" << endl;

    LPVOID baseAddrOfAllcRgn = VirtualAllocEx(process, actualAddr, dwSize, MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
    if(baseAddrOfAllcRgn == NULL)
    {
        cout << "VirtualAllocEx hat ein Problem: " << GetLastError() << endl;
        return 0;
    }
    else
        cout << "VirtualAllocEx hat speicher reserviert" << endl;


    SIZE_T nBytesWritten;

    if(WriteProcessMemory(process, baseAddrOfAllcRgn, (LPCVOID)&injParameter, sizeof(INJECTPARAMETER), &nBytesWritten) == 0)
    {
        cout << "struct konnte nicht an die angegebene addresse geschrieben werden: " << GetLastError() << endl;
        return 0;
    }
    else
        cout << "struct wurde mit " << nBytesWritten << " an die Addresse geschrieben." << endl;

    if(WriteProcessMemory(process, (LPVOID)((DWORD)baseAddrOfAllcRgn+sizeof(INJECTPARAMETER)+7), (LPCVOID)&injectedThread, InjThreadSize, &nBytesWritten) == 0)
    {
        cout << "WriteProcessMemory hat ein Problem: " << GetLastError() << endl;
        return 0;
    }
    else
        cout << "WriteProcessMemory: " << nBytesWritten << " nBytesWritten" << endl;

    cout << "Nun kommt CreateRemoteThread: "; getchar();
    //return 0;   //Befindet sich vorläufig hier, weil im moment CreateRemoteThread das Programm sonst zum absturz bringen würde

    LPDWORD lpNULL;
    //Hypothese zu dem Parameter, den CreateRemoteThread an injectedThread übergibt:
    //musste eigentlich im moment eine hardgecodete Addresse sein, welche sich noch auf den nicht injecteted Process bezieht
    //und die struct nicht richtig übergeben wird.
    //daher eventuell baseAddrOfAllcRgn übergeben, weil dorthin die struct geschriben wird
    HANDLE hThread = CreateRemoteThread(process, 0, 0, (LPTHREAD_START_ROUTINE)injectedThread, (LPVOID)&injParameter, 0, lpNULL);
    if(hThread == NULL)
    {
        cout << "CreateRemoteThread hat ein Problem: " << GetLastError() << endl;
    }
    else
    {
        cout << "hTread = " << hThread << endl;
    }

    return 0;
}

void injectedThread(INJECTPARAMETER *p)
{
    //Kein unerwünschter call mehr ;)
    //char cPtr[] = {'u','s','e','r','3','2','.','d','l','l'};

    p->loadlibraryA(p->cDll);
    p->msgBoxA(0, p->cCaption, p->cText, 0);
    p->exitprocess(0);
}

void injectedThread_end()
{
    //Ist nur dafür da, um die größe von injectedThread() rauszubekommen
}

bool enableSeDebugPrivilege()
{
    HANDLE myProcess = GetCurrentProcess();
    TOKEN_PRIVILEGES pri;
    LUID luid;

    if(LookupPrivilegeValue(0, "seDebugPrivilege", &luid) == 0)
    {
        cout << "SE_PRIV: LookupPrivilegeValue: " << GetLastError() << endl;
        return false;
    }

    pri.PrivilegeCount = 0;
    pri.Privileges[0].Luid = luid;
    pri.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if(AdjustTokenPrivileges(myProcess, false, &pri, sizeof(TOKEN_PRIVILEGES), 0, 0) == 0)
    {
        cout << "SE_PRIV: AdjustTokenPrivileges: " << GetLastError() << endl;
        return false;
    }

    cout << "SeDebugPrivilege erfolgreich erhalten." << endl;

    CloseHandle(myProcess);

    return true;
}

 
Wenn du Win7 benutzt, muss dein Programm als Administrator gestartet werden. Außerdem könnte die Codeinjection an ASLR scheitern, ich bin mir nicht sicher, aber es könnte sein, dass die Bibliotheken pro Prozess an eine andere Speicheradresse geladen werden.
 
Das mit Administratorrechten hab ich eben ausprobiert, daran kann es nicht liegen. Auch mit Admin rechten bekomm ich den Fehler ERROR_INVALID_HANDLE. Das mit dem ASLR hab ich jetzt mal eben kurz überflogen, denke aber das es daran nicht liegen kann, dass ich das SeDebugPrivilege erhalte. Inwiefern es die CodeInjection verhindert kann ich noch nicht sagen.

Kann es vielleicht sein, das es nicht möglich ist, dass SeDebugPrivilege von seinem eigenem Prozess zu ändern?
 
UPDATE:
Ok, das SeDebugPrivilege erhalte ich jetzt, aber aber VirtualAllocEx liefert mir nun den Fehler 487 ("Attempt to access invalid address."), auch wenn ich ds Programm als Administrator starte. Woran kann das den noch liegen? Ich dachte die nötigen Rechte hätte ich damit, und die gefundenen Bytes sind doch MEM_FREE...

Hier nun der überarbeitete Code der Funktion, die mir das nötige Privilege brachte:
Code:
bool gettingSeDebugPrivilege()
{
    HANDLE hToken, myProcess = GetCurrentProcess();
    TOKEN_PRIVILEGES pri;
    LUID luid;

    OpenProcessToken(myProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);

    if(LookupPrivilegeValue(0, "seDebugPrivilege", &luid) == 0)
    {
        cout << "SE_PRIV: LookupPrivilegeValue: " << GetLastError() << endl;
        return false;
    }

    pri.PrivilegeCount = 0;
    pri.Privileges[0].Luid = luid;
    pri.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if(AdjustTokenPrivileges(hToken, false, &pri, sizeof(TOKEN_PRIVILEGES), 0, 0) == 0)
    {
        cout << "SE_PRIV: AdjustTokenPrivileges: " << GetLastError() << endl;
        return false;
    }

    cout << "SeDebugPrivilege erfolgreich erhalten." << endl;

    CloseHandle(myProcess);
    CloseHandle(hToken);
    return true;
}
 
ASLR sollte erstmal nur bei Systemneustart andere Adressen für die Systemdlls vergeben - so habe ich das jedenfalls verstanden.

Allerdings dürfte wie schon bei XP gelten, dass man (wenn überhaupt) sich nur auf Adressen der ntdll und kernel32 Module verlassen sollte. MessageBox Adresse sollte man also optimalerweise im Injection-Code herausfinden.



2. Das ganze mal mit dem aktuellen VS C++[0] compiliert und debuggt:

2.1
Code:
 DWORD InjThreadSize = reinterpret_cast<intptr_t>(&injectedThread_end) - reinterpret_cast<intptr_t>(&injectedThread);
ergibt 4294967256 (also Integer underflow, Aufgrund der "willkürlich" platzierten Funktionen.

Hier sollte man sich dann doch etwas anderes überlegen (fürs erste reicht es aus, die Größe per Hand zu setzen = 0x1000 sollte ausreichen). Hilft bei mir im Übrigen nichts, Optimierungen & Co abzuschalten (eventuell übersehe ich noch irgendwelche MS spezifischen Flags, um compilerspezifische Features kommt man hier wohl nicht herum).

2.2
AdjustTokenPrivileges braucht einen Token. Kein Prozesshandle. Also:
Code:
bool enableSeDebugPrivilege()
{
    HANDLE myProcess = GetCurrentProcess();
    HANDLE hToken;
     
    TOKEN_PRIVILEGES pri;
    LUID luid;

    if(OpenProcessToken(myProcess,TOKEN_ADJUST_PRIVILEGES |TOKEN_QUERY, &hToken) == 0)
    {
        cout << "SE_PRIV: OpenProcessToken error :( " << GetLastError() << endl;
    }
... ab hier wie im original ...
    if(LookupPrivilegeValue(0, "seDebugPrivilege", &luid) == 0)
Im übrigen muss man kein Admin sein - nur das Konto/Benutzergruppe sollte dieses Privileg besitzen.

2.3:
Die Adresse bei VirtualAlloc(Ex) ist im übrigen optional (ja, es fällt mir etwas spät ein ;) ) - wird da eine NULL übergeben, so wird der Bereich vom System gesucht/reserviert.

HANDLE hThread = CreateRemoteThread(process, 0, 0, (LPTHREAD_START_ROUTINE)injectedThread, (LPVOID)&injParameter, 0, lpNULL);
Hm, immer noch nicht. CreateRemotThread möchte
1) adresse der Funktion im Prozessraum
2) Flags zum Starten
haben und kann netterweise 1 Parameter an die gestartete Funktion übergeben.

Um es einfach zu halten: 2 mal VirtualAllocEx ausführen (siehe Code am Ende des Posts), Parameter und Threadcode heineinschreiben und CreateRemoteThread mit den Adressen, die VirtualAllocEx zurückgegeben hat (und die man mittelw WriteProcessMemory mit etwas sinnvollem beschrieben hat) ausführen.


Als MSVC++ Nutzer sollte man folgendes beachten - unter "Debug" Build zeigt
"&function" auf eine Adress-JMP Tabelle:
Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
00821005   $-/E9 26390000   JMP _setdefaultprecision
0082100A   .-|E9 D1100000   JMP injectedThread_end
0082100F   $-|E9 BC390000   JMP _setargv
00821014   $-|E9 F7100000   JMP enableSeDebugPrivilege
die auch entsprechend von "MemoryWrite" brav kopiert wird (und das Programm entsprechend crasht).
Als Release-Build funktioniert es aber wie erwartet.


Funktionierender Code (getestet mit Microsoft Visual C++ 2010, man sollte allerdings unter Projecteinstellungen Unicode abstellen)

Code:
// CodeInjectionText.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//

#include "stdafx.h"


#include <iostream>
#include <windows.h>

using namespace std;

typedef HMODULE (WINAPI *LOADLIBRARYA)(LPCTSTR);
typedef int (WINAPI *MESSAGEBOXA)(HWND, LPCTSTR, LPCTSTR, UINT);
typedef void (WINAPI *EXITPROCESS)(UINT);

struct INJECTPARAMETER
{
    MESSAGEBOXA msgBoxA;
    LOADLIBRARYA loadlibraryA;
    EXITPROCESS exitprocess;
    char cCaption[15];
    char cText[15];
    char cDll[11];
};

void injectedThread(INJECTPARAMETER *p);
void injectedThread_end();
bool enableSeDebugPrivilege();

int main()
{
    HANDLE process;

    INJECTPARAMETER injParameter;
    strcpy(injParameter.cCaption, "Caption");
    strcpy(injParameter.cText, "Hallo Welt");
    strcpy(injParameter.cDll, "user32.dll");
    injParameter.loadlibraryA = (LOADLIBRARYA)GetProcAddress(LoadLibrary("kernel32.dll"), "LoadLibraryA");
    injParameter.msgBoxA = (MESSAGEBOXA) GetProcAddress(LoadLibrary("user32.dll"), "MessageBoxA");
    injParameter.exitprocess = (EXITPROCESS) GetProcAddress(LoadLibrary("kernel32.dll"), "ExitProcess");

    //Wie groß ist die Funktion injectedThread?
    DWORD InjThreadSize = 0x1000;//DWORD(&injectedThread_end) - DWORD(&injectedThread);
    cout << "Differenz: " << InjThreadSize << endl;

    STARTUPINFO         startupInfo;
    PROCESS_INFORMATION processInfo;

    ZeroMemory(&startupInfo, sizeof(startupInfo));
    ZeroMemory(&processInfo, sizeof(processInfo));

    /*char szExe[] = "D:\\OllyDbg 2.0\\ollydbg.exe";
    if(CreateProcess((LPCTSTR)szExe, 0, 0, 0, false, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, 0, 0, &startupInfo, &processInfo) != 0)
    {
    cout << "CreateProcess war erfolgreich" << endl;
    }
    else
    {
    cout << "CreateProcess war nicht erfolgreich: " << GetLastError() << endl;
    return 0;
    }

    process = processInfo.hProcess;*/
    process = GetCurrentProcess();
    if(process == 0)
        cout << "Process konnte nicht geoeffnet werden" << endl;
    else
        cout << "Process geoeffnet" << endl;

    if(enableSeDebugPrivilege() != true)
    {
        cout << "SeDebugPrivilege nicht erhalten" << endl;
        return 0;
    }

    DWORD dwSize = 0x1000;

    LPVOID remoteThreadAddr = VirtualAllocEx(process,0, dwSize, MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
    if(remoteThreadAddr == NULL)
    {
        cout << "VirtualAllocEx hat ein Problem: " << GetLastError() << endl;
        return 0;
    }
    else
        cout << "VirtualAllocEx hat speicher reserviert" << endl;

    LPVOID remoteThreadParams = VirtualAllocEx(process,0, sizeof(INJECTPARAMETER), MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
    if(remoteThreadParams == NULL)
    {
        cout << "VirtualAllocEx fuer remoteThreadParams hat ein Problem: " << GetLastError() << endl;
        return 0;
    }
    else
        cout << "VirtualAllocEx hat speicher reserviert" << endl;


    SIZE_T nBytesWritten;

    if(WriteProcessMemory(process, remoteThreadParams, (LPCVOID)&injParameter, sizeof(INJECTPARAMETER), &nBytesWritten) == 0)
    {
        cout << "struct konnte nicht an die angegebene addresse geschrieben werden: " << GetLastError() << endl;
        return 0;
    }
    else
        cout << "struct wurde mit " << nBytesWritten << " an die Addresse geschrieben." << endl;

    if(WriteProcessMemory(process, remoteThreadAddr, (LPCVOID)&injectedThread, InjThreadSize, &nBytesWritten) == 0)
    {
        cout << "WriteProcessMemory hat ein Problem: " << GetLastError() << endl;
        return 0;
    }
    else
        cout << "WriteProcessMemory: " << nBytesWritten << " nBytesWritten" << endl;

    cout << "Nun kommt CreateRemoteThread: "; getchar();
    //return 0;   //Befindet sich vorläufig hier, weil im moment CreateRemoteThread das Programm sonst zum absturz bringen würde


    HANDLE hThread = CreateRemoteThread(process, 0, 0, (LPTHREAD_START_ROUTINE)remoteThreadAddr, remoteThreadParams, 0, NULL);
    if(hThread == NULL)
    {
        cout << "CreateRemoteThread hat ein Problem: " << GetLastError() << endl;
    }
    else
    {
        cout << "hTread = " << hThread << endl;
    }
    /* sonst sieht man nix von der MessageBox */
    WaitForSingleObject(hThread,30000);
    return 0;
}

void injectedThread(INJECTPARAMETER *p)
{
    //Kein unerwünschter call mehr ;)
    //char cPtr[] = {'u','s','e','r','3','2','.','d','l','l'};

    p->loadlibraryA(p->cDll);
    p->msgBoxA(0, p->cCaption, p->cText, 0);
    p->exitprocess(0);
}

void injectedThread_end()
{
    //Ist nur dafür da, um die größe von injectedThread() rauszubekommen
}

bool enableSeDebugPrivilege()
{
    HANDLE myProcess = GetCurrentProcess();
    HANDLE hToken;

    TOKEN_PRIVILEGES pri;
    LUID luid;

    if(OpenProcessToken(myProcess,TOKEN_ADJUST_PRIVILEGES |TOKEN_QUERY, &hToken) == 0)
    {
        cout << "SE_PRIV: OpenProcessToken error :( " << GetLastError() << endl;
    }
    if(LookupPrivilegeValue(0, "seDebugPrivilege", &luid) == 0)
    {
        cout << "SE_PRIV: LookupPrivilegeValue: " << GetLastError() << endl;
        return false;
    }

    pri.PrivilegeCount = 0;
    pri.Privileges[0].Luid = luid;
    pri.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if(AdjustTokenPrivileges(hToken, false, &pri, sizeof(TOKEN_PRIVILEGES), 0, 0) == 0)
    {
        cout << "SE_PRIV: AdjustTokenPrivileges: " << GetLastError() << endl;
        return false;
    }

    cout << "SeDebugPrivilege erfolgreich erhalten." << endl;

    CloseHandle(myProcess);

    return true;
}


[0] eigentlich wegen der guten Debuggerintegration.

Edit:
gut, das mit den DebugPrivilege hat sich anscheinend erledigt.
 
Okay, deine Version läuft bei mir auch. Vielen Dank für die Hilfe schonmal :wink:. Dennoch möchte ich kurz noch auf ein paar Sachen eingehen, die mir unklar sind. Schließlich will ich ja was lernen und nicht einfach nur eine Code injection durchführen und dann Copy&Paste.

Code:
DWORD InjThreadSize = reinterpret_cast<intptr_t>(&injectedThread_end) - reinterpret_cast<intptr_t>(&injectedThread);
Ich gehe mal davon aus, dass das bei MSVC++ auftritt, da die Funktionen nicht der Reihe nach angeordnet werden. gcc liefert mir jedenfalls da den richtigen Wert. Aber gut, das ist ja nur ne Kleinigkeit...

Zum eigentlichen:
[1]: VirtualAllocEx sucht ohne die Angabe des zweiten Parameters (also 0) doch nach Speicher der als MEM_FREE gelistet ist. Halt genau das selbe was ich vorher mit meiner VirtualQueryEx getan hab.
Nun gut, wenn ich zweimal VirtualAllocEx aufrufe, sowohl für die Parameterstruktur als auch für den eigentlichen Code, erhalte ich zwei Addressen zu den jeweiligen Daten, die ich dann an CreateRemoteThread übergebe, nachdem die Daten mit WriteProcessMemory() an die Addressen geschrieben wurden.

Nun aber mal angenommen:
Ich finde mit VirtualQueryEx freien Speicher der groß genug für beide Datenpaare ist und reserviere diesen Speicher mit VirtualAllocEx. Dann habe ich eine Addresse addr an die ich zuerst meine INJECTSTRUCT schreibe und eine Addresse addr+sizeof(INJECTSTRUCT) an die ich meinen Thread schreibe. Wenn ich anschließend beide Addressen an CreateRemoteThread() übergebe, müsste das doch äquivalent zu der Methode [1] sein, oder (abgesehen davon, das bei [1] die Datenpaare nicht zwingend nebeneinanderliegen)?
 
Code:
DWORD InjThreadSize = reinterpret_cast<intptr_t>(&injectedThread_end) - reinterpret_cast<intptr_t>(&injectedThread);
Ich gehe mal davon aus, dass das bei MSVC++ auftritt, da die Funktionen nicht der Reihe nach angeordnet werden. gcc liefert mir jedenfalls da den richtigen Wert. Aber gut, das ist ja nur ne Kleinigkeit...
Jep. Aber rein vom Compilerverhalten ist es (afaik) nirgendwo vorgeschrieben. Man setzt damit also auf ein bestimmtes Compilerverhalten ;)

Zum eigentlichen:
[1]: VirtualAllocEx sucht ohne die Angabe des zweiten Parameters (also 0) doch nach Speicher der als MEM_FREE gelistet ist. Halt genau das selbe was ich vorher mit meiner VirtualQueryEx getan hab.
Vergiss das, was ich über die kleinste Einheit, die VirtualAlloc reservieren kann, geschrieben habe. Das war inkorrekt (bzw. hatte es nichts mit dem Fehler zu tun).

Die Ursache für den Fehler sollte hier liegen: SYSTEM_INFO
SYSTEM_INFO structure
dwAllocationGranularity The granularity for the starting address at which virtual memory can be allocated. For more information, see VirtualAlloc.
lpAddress [in, optional] The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary. To determine the size of a page and the allocation granularity on the host computer, use the GetSystemInfo function. If this parameter is NULL, the system determines where to allocate the region.
Die Startadresse darf also nicht ganz beliebig sein. Wenn man den Suchcode ändert:
Code:
        if(memInfo.State == MEM_FREE && ((SIZE_T)memInfo.BaseAddress % info.dwAllocationGranularity == 0))
            break;
klappt es auch.


Nun aber mal angenommen:
Ich finde mit VirtualQueryEx freien Speicher der groß genug für beide Datenpaare ist und reserviere diesen Speicher mit VirtualAllocEx. Dann habe ich eine Addresse addr an die ich zuerst meine INJECTSTRUCT schreibe und eine Addresse addr+sizeof(INJECTSTRUCT) an die ich meinen Thread schreibe. Wenn ich anschließend beide Addressen an CreateRemoteThread() übergebe, müsste das doch äquivalent zu der Methode [1] sein, oder (abgesehen davon, das bei [1] die Datenpaare nicht zwingend nebeneinanderliegen)?
Da sehe ich im Moment keine Denkfehler. Bissel mehr Aufwand und man sollte schön aufpassen beim Rechnen.
Der Ansatz mit 2x VirtualAllocEx ist bloß etwas besser zum Debuggen gewesen ;)
 
Zurück
Oben