Programm im Speicher erzeugen und ausführen
-
man könnte ja auch ein paar dateifunktionen ala CreateFile irgentwie
über inlinehooking oder sowas umbauen, so dass sie nicht auf die platte
sondern den ram zugreifen. habe ich mal versucht, aber aufgegeben, weil
ich die olle "kernel32.dll" nicht unprotecten konntekönnte aber klappen (theroetisch)
-
Weiß nicht ob das so ohne Weiteres funktioniert, du könntest aber mal VirtualAlloc mit PAGE_EXECUTE_READWRITE als memory-protection versuchen.
Also deine Daten, die du empfängst in den mit VirtualAlloc angeforderten Speicherbereich schreiben und dann ausführen. Funktioniert so natürlich nicht, da EXE-Dateien ja nicht nur ausführbaren Code enthalten. Vielleicht kannst du deine empfangenen Daten ja noch so abändern, dass du in den Speicherbereich gleich ausführbaren Code reinschreibst.Na gut, das ist wohl nicht die beste (oder kürzeste) Lösung, war auch nur so ein Gedanke...
-
AntonWert schrieb:
Das Programme aus dem Speicher heraus aufgerufen werden können muss gehen!
Blaaaaaaaaaaah
Beispiel: Auf der Arbeit hab ich so nen netten Fall, da ist die Exe verschlüsslet auf der Platte, ein Dongel entschlüsselt sie und das Ladeprogramm führt es aus. Speziell in diesem Fall währe es sehr sehr unschön wenn die entschlüsslte exe auf der Festplatte rumliegt...
Aber wie geht das?
Das ist was anderes. In dem Fall ist ein Teil des Programms immernoch unverschlüsselt, nämlich die PE-Header, einige PE Datenstrukturen, sowie ein kleiner Programmschnippsel, der den Verschlüsselten Teil mit Hilfe des Dongles entschlüsselt etc.
DAS geht. Ist aber a) was gänzlich anderes und b) ziemlich kompliziert.
-
Bier schrieb:
Vielleicht kannst du deine empfangenen Daten ja noch so abändern, dass du in den Speicherbereich gleich ausführbaren Code reinschreibst.
Das kann gehen. Allerdings muss dazu der Code Position-Independant sein. Bei x64 kein Problem, bei x86 eher schon. Oder man kann natürlich eigene Relocation-Tables mitschicken. Auf jeden Fall auch nicht ganz trivial.
p.S.: und irgendeine Art wie der versendete Code an DLL-Importe rankommt muss man sich auch einfallen lassen. Also z.B. einen eigenen Import-Table mitschicken (und auflösen bevor man den Code ausführt). Oder die Adressen der Funktionen LoadLibrary + GetProcAddress mitgeben, und den Code alles dynamisch laden lassen (umständlich, aber möglich).
-
am besten wäre es ja einfach den windows-loader umzubauen. (wurde glaubich schon
erwäht). scheint aber nicht zu klappen, als normaluser ohne debugrechte, etc.
darf ich nicht im addressraum von kernel32 rumschreiben, VirtualProtect meldet
immer access_deinded. (code: 998). eben getestet.bekommt jeder prozess eine kopie von kernel32 oder wird die dll einfach nur
in den prozess eingeblendet?kann man nicht einfach die ganze funktion irgentwie auslesen und woanders
ausführen? (nach relocation).da muss es doch was geben, wäre die eleganteste lösung
-
^^man könnte 'createprocess' nachbauen bzw. abändern. für die exe wird ja ein 'section objekt' (auch als filemapping bekannt) angelegt. da könnte man vielleicht ansetzen und eine dateilose section (CreateFileMapping() ohne gültiges file-handle aufrufen) erzeugen, die man dann mit den daten der exe füttert. hört sich nach viel bastelei an, wär aber sicherlich interessant, sich 'ne CreateMemoryProcess()-funktion zu bauen.
-
@AntonWert: Das geht ungefähr in drei-vier Schritten, Speicher allokieren (1), Deine Daten, die ja ausführbaren Code darstellen, rüberkopieren (2), den Speicherbereich als ausführbar "einstellen" und Funktionspointer darauf (3) setzen:
{ void (*my_func)(void) = NULL; void *pMem = NULL; void *pDeineDaten = NULL; DWORD ManyBytes = 4096; DWORD OldProtect = 0; ... /* pDeineDaten mit Daten füllen */ pMem = VirtualAlloc(NULL, ManyBytes, MEM_COMMIT, PAGE_READWRITE); memcpy(pMem, pDeineDaten, ManyBytes); VirtualProtect(pMem, ManyBytes, PAGE_EXECUTE, &OldProtect); my_func = (void (*)(void))pMem; my_func(); }
Viel Glück beim Debuggen!
-
abc.w schrieb:
@AntonWert: Das geht ungefähr in drei-vier Schritten, Speicher allokieren (1), Deine Daten, die ja ausführbaren Code darstellen, rüberkopieren (2), den Speicherbereich als ausführbar "einstellen" und Funktionspointer darauf (3) setzen:
{ void (*my_func)(void) = NULL; void *pMem = NULL; void *pDeineDaten = NULL; DWORD ManyBytes = 4096; DWORD OldProtect = 0; ... /* pDeineDaten mit Daten füllen */ pMem = VirtualAlloc(NULL, ManyBytes, MEM_COMMIT, PAGE_READWRITE); memcpy(pMem, pDeineDaten, ManyBytes); VirtualProtect(pMem, ManyBytes, PAGE_EXECUTE, &OldProtect); my_func = (void (*)(void))pMem; my_func(); }
Viel Glück beim Debuggen!
^^ so kannste aber keine 'richtige exe' ausführen.
-
das klappt so nicht. zum einen, weil die relocaton fehlt und zum anderen weil die
echse einen header hat, den du mitausführen willst.
-
Ach so, eine richtige exe soll es sein, habe ich überlesen. Dann... keine Ahnung...
-
vielleicht schaust mal im ReactOS source code wie CreateProcess() funktioniert, da die exe ja sowieso zuerst in den speicher geladen wird damit sie überhaupt ausführbar ist. alles andere sollte sich dann ergeben, oder FreeDOS wie die exe laden... etc..
-
mittlerweile habe ich es geschafft, kernel32 funktionen erfolgreich
umzubiegen. allerdings scheint weder CreateProcess noch LoadLibrary
auf dateifunktionen wie CreateFile zurückzugreifen.wie machen die das? ich versuche grade die ntdll funktionen zu hooken.
vielleicht klappt das ja.
-
du musst dazu nicht zwingend createprocess umschreiben,es sind nur folgende schritte nötig:
- .exe einlesen (optional)
- entsprechend speicher allocieren für dos/ntheader
- header in allocierten speicher kopieren,sections richtig erstellen
- STARTUPINFO/PROCESS_INFORMATION/CONTEXT richtig setzen
- CreateProcess aufrufenpoc code dazu:
//-------------------------------------------------------- // Dynamic Process Forking of Portable Executable // Author : Vrillon / Venus // Date : 07/14/2008 //-------------------------------------------------------- /*********************************************************/ /* With this header, you can create and run a process */ /* from memory and not from a file. */ /*********************************************************/ #ifdef WIN32 #include <windows.h> #else #error Process Forking Requires a Windows Operating System #endif #include <stdio.h> ///////////////////////////////////////////////////////////// // NtUnmapViewOfSection (ZwUnmapViewOfSection) // Used to unmap a section from a process. typedef long int (__stdcall* NtUnmapViewOfSectionF)(HANDLE,PVOID); NtUnmapViewOfSectionF NtUnmapViewOfSection = (NtUnmapViewOfSectionF)GetProcAddress(LoadLibrary("ntdll.dll"),"NtUnmapViewOfSection"); ///////////////////////////////////////////////////////////// // Fork Process // Dynamically create a process based on the parameter 'lpImage'. The parameter should have the entire // image of a portable executable file from address 0 to the end. bool ForkProcess(LPVOID lpImage) { // Variables for Process Forking long int lWritten; long int lHeaderSize; long int lImageSize; long int lSectionCount; long int lSectionSize; long int lFirstSection; long int lPreviousProtection; long int lJumpSize; bool bReturnValue; LPVOID lpImageMemory; LPVOID lpImageMemoryDummy; IMAGE_DOS_HEADER dsDosHeader; IMAGE_NT_HEADERS ntNtHeader; IMAGE_SECTION_HEADER shSections[512 * 2]; PROCESS_INFORMATION piProcessInformation; STARTUPINFO suStartUpInformation; CONTEXT cContext; // Variables for Local Process FILE* fFile; char* pProcessName; long int lFileSize; long int lLocalImageBase; long int lLocalImageSize; LPVOID lpLocalFile; IMAGE_DOS_HEADER dsLocalDosHeader; IMAGE_NT_HEADERS ntLocalNtHeader; ///////////////////////////////////////////////////////////////// // End Variable Definition bReturnValue = false; pProcessName = new char[MAX_PATH]; ZeroMemory(pProcessName,MAX_PATH); // Get the file name for the dummy process if(GetModuleFileName(NULL,pProcessName,MAX_PATH) == 0) { delete [] pProcessName; return bReturnValue; } // Open the dummy process in binary mode fFile = fopen(pProcessName,"rb"); if(!fFile) { delete [] pProcessName; return bReturnValue; } fseek(fFile,0,SEEK_END); // Get file size lFileSize = ftell(fFile); rewind(fFile); // Allocate memory for dummy file lpLocalFile = new LPVOID[lFileSize]; ZeroMemory(lpLocalFile,lFileSize); // Read memory of file fread(lpLocalFile,lFileSize,1,fFile); // Close file fclose(fFile); // Grab the DOS Headers memcpy(&dsLocalDosHeader,lpLocalFile,sizeof(dsLocalDosHeader)); if(dsLocalDosHeader.e_magic != IMAGE_DOS_SIGNATURE) { delete [] pProcessName; delete [] lpLocalFile; return bReturnValue; } // Grab NT Headers memcpy(&ntLocalNtHeader,(LPVOID)((long int)lpLocalFile+dsLocalDosHeader.e_lfanew),sizeof(dsLocalDosHeader)); if(ntLocalNtHeader.Signature != IMAGE_NT_SIGNATURE) { delete [] pProcessName; delete [] lpLocalFile; return bReturnValue; } // Get Size and Image Base lLocalImageBase = ntLocalNtHeader.OptionalHeader.ImageBase; lLocalImageSize = ntLocalNtHeader.OptionalHeader.SizeOfImage; // Deallocate delete [] lpLocalFile; // Grab DOS Header for Forking Process memcpy(&dsDosHeader,lpImage,sizeof(dsDosHeader)); if(dsDosHeader.e_magic != IMAGE_DOS_SIGNATURE) { delete [] pProcessName; return bReturnValue; } // Grab NT Header for Forking Process memcpy(&ntNtHeader,(LPVOID)((long int)lpImage+dsDosHeader.e_lfanew),sizeof(ntNtHeader)); if(ntNtHeader.Signature != IMAGE_NT_SIGNATURE) { delete [] pProcessName; return bReturnValue; } // Get proper sizes lImageSize = ntNtHeader.OptionalHeader.SizeOfImage; lHeaderSize = ntNtHeader.OptionalHeader.SizeOfHeaders; // Allocate memory for image lpImageMemory = new LPVOID[lImageSize]; ZeroMemory(lpImageMemory,lImageSize); lpImageMemoryDummy = lpImageMemory; lFirstSection = (long int)(((long int)lpImage+dsDosHeader.e_lfanew) + sizeof(IMAGE_NT_HEADERS)); memcpy(shSections,(LPVOID)(lFirstSection),sizeof(IMAGE_SECTION_HEADER)*ntNtHeader.FileHeader.NumberOfSections); memcpy(lpImageMemoryDummy,lpImage,lHeaderSize); // Get Section Alignment if((ntNtHeader.OptionalHeader.SizeOfHeaders % ntNtHeader.OptionalHeader.SectionAlignment) == 0) { lJumpSize = ntNtHeader.OptionalHeader.SizeOfHeaders; } else { lJumpSize = (ntNtHeader.OptionalHeader.SizeOfHeaders/ntNtHeader.OptionalHeader.SectionAlignment); lJumpSize += 1; lJumpSize *= (ntNtHeader.OptionalHeader.SectionAlignment); } lpImageMemoryDummy = (LPVOID)((long int)lpImageMemoryDummy + lJumpSize); // Copy Sections To Buffer for(lSectionCount = 0; lSectionCount < ntNtHeader.FileHeader.NumberOfSections; lSectionCount++) { lJumpSize = 0; lSectionSize = shSections[lSectionCount].SizeOfRawData; memcpy(lpImageMemoryDummy,(LPVOID)((long int)lpImage + shSections[lSectionCount].PointerToRawData),lSectionSize); if((shSections[lSectionCount].Misc.VirtualSize % ntNtHeader.OptionalHeader.SectionAlignment)==0) { lJumpSize = shSections[lSectionCount].Misc.VirtualSize; } else { lJumpSize = (shSections[lSectionCount].Misc.VirtualSize/ntNtHeader.OptionalHeader.SectionAlignment); lJumpSize += 1; lJumpSize *= (ntNtHeader.OptionalHeader.SectionAlignment); } lpImageMemoryDummy = (LPVOID)((long int)lpImageMemoryDummy + lJumpSize); } ZeroMemory(&suStartUpInformation,sizeof(STARTUPINFO)); ZeroMemory(&piProcessInformation,sizeof(PROCESS_INFORMATION)); ZeroMemory(&cContext,sizeof(CONTEXT)); suStartUpInformation.cb = sizeof(suStartUpInformation); // Create Process if(CreateProcess(NULL,pProcessName,NULL,NULL,false,CREATE_SUSPENDED,NULL,NULL,&suStartUpInformation,&piProcessInformation)) { cContext.ContextFlags = CONTEXT_FULL; GetThreadContext(piProcessInformation.hThread,&cContext); // Check image base and image size if(lLocalImageBase == (long int)ntNtHeader.OptionalHeader.ImageBase && lImageSize <= lLocalImageSize) { VirtualProtectEx(piProcessInformation.hProcess,(LPVOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lImageSize,PAGE_EXECUTE_READWRITE,(unsigned long*)&lPreviousProtection); } else { if(!NtUnmapViewOfSection(piProcessInformation.hProcess,(LPVOID)((DWORD)lLocalImageBase))) VirtualAllocEx(piProcessInformation.hProcess,(LPVOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lImageSize,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE); } // Write Image to Process if(WriteProcessMemory(piProcessInformation.hProcess,(LPVOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lpImageMemory,lImageSize,(unsigned long*)&lWritten)) { bReturnValue = true; } // Set Image Base if(WriteProcessMemory(piProcessInformation.hProcess,(LPVOID)((long int)cContext.Ebx + 8),&ntNtHeader.OptionalHeader.ImageBase,4,(unsigned long*)&lWritten)) { if(bReturnValue == true) bReturnValue = true; } if(bReturnValue == false) { delete [] pProcessName; delete [] lpImageMemory; return bReturnValue; } // Set the new entry point cContext.Eax = ntNtHeader.OptionalHeader.ImageBase + ntNtHeader.OptionalHeader.AddressOfEntryPoint; SetThreadContext(piProcessInformation.hThread,&cContext); if(lLocalImageBase == (long int)ntNtHeader.OptionalHeader.ImageBase && lImageSize <= lLocalImageSize) VirtualProtectEx(piProcessInformation.hProcess,(LPVOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lImageSize,lPreviousProtection,0); // Resume the process ResumeThread(piProcessInformation.hThread); } delete [] pProcessName; delete [] lpImageMemory; return bReturnValue; } ///////////////////////////////////////////////////////////// // Fork Process From Resource // Dynamically create a process from a resource file. bool ForkProcessFromResource(int iResource,char* pResourceSection) { HGLOBAL hResData; HRSRC hResInfo; LPVOID lpRes; LPVOID lpMemory; long int lSize; HMODULE hModule; bool bReturn; hModule = GetModuleHandle(0); bReturn = false; if(!hModule) return bReturn; hResInfo = FindResource(hModule, MAKEINTRESOURCE(iResource), pResourceSection); if(!hResInfo) { return bReturn; } hResData = LoadResource(hModule, hResInfo); if(!hResData) { return bReturn; } lpRes = LockResource(hResData); if(!lpRes) { FreeResource(hResData); return bReturn; } lSize = SizeofResource(hModule, hResInfo); lpMemory = new LPVOID[lSize]; ZeroMemory(lpMemory,lSize); memcpy (lpMemory, lpRes, lSize); bReturn = ForkProcess(lpMemory); FreeResource(hResData); delete [] lpMemory; return bReturn; }
-
puh ganz schön viel code. warum greift der den nicht auf die datei zu?
schließlich übergibst du ihm ja einen (eigenen) dateipfad?
-
helferlein schrieb:
warum greift der den nicht auf die datei zu? schließlich übergibst du ihm ja einen (eigenen) dateipfad?
Grob gesagt erzeugt das Snippet "irgendeinen" Prozess und brezelt dann seine "RAM-EXE" rein.
-
wird bei diesem "irgenteinem" prozess nicht aber auf die platte zurückgegriffen?
-
Ja, wird auch. Ist gewissermaßen "Hijacking". Insofern ist es nicht grade im Sinne des OT.
-
wo wird da eine exe von der HD geladen ?
oder hab ich da was nicht gesehen?
-
zweiter parameter von CreateProcess....
-
heutemalwasanderes schrieb:
wo wird da eine exe von der HD geladen ?
Er lädt sich selbst als "dummy process" ("irgendeiner" geht auch):
if(GetModuleFileName(NULL,pProcessName,MAX_PATH) == 0) ... (...) // Zugriff! -> verloren,verloren,hihihi :) if(CreateProcess(NULL,pProcessName,NULL,NULL,false,CREATE_SUSPENDED, ...