Czy kod po włączeniu może wytworzyć inny kod maszynowy i włączyć go w osobnym wątku ?
Tak.
Oczywiscie.
- Co tylko zechcesz
- CreateThread()
Jak się tendencja utrzyma (jedno zdanie więcej niż poprzednik) to w tym wątku coś więcej pojawi się za miesiąc.
Ja jak zwykle z naklepanym w kilkanaście minut przykładem, 'małym', 'użytecznym' i 'poprawnym politycznie'.
#include <windows.h>
#include <iostream>
using namespace std;
// nie wszystkie kompilatory maja tak 'nowoczesne' naglowki zeby miec te flage
#define HEAP_CREATE_ENABLE_EXECUTE 0x00040000
class ShowMessageBox {
static class ExecutableHeap {
HANDLE executableHeap;
public:
void* alloc(size_t size) {
return HeapAlloc(executableHeap, 0, size);
}
void free(void *ptr) {
HeapFree(executableHeap, 0, ptr);
}
ExecutableHeap()
: executableHeap(HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0)) {}
~ExecutableHeap() {
HeapDestroy(executableHeap);
}
} executableHeap;
#pragma pack(push, 1)
struct Code {
BYTE bPushd1; DWORD dwType;
BYTE bPushd2; DWORD dwCaption;
BYTE bPushd3; DWORD dwText;
BYTE bPushd4; DWORD dwHWND;
BYTE bCallOff; DWORD dwAddress;
BYTE bRetn; WORD wRetSize;
} *code;
#pragma pack(pop)
public:
ShowMessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
code = (Code*) executableHeap.alloc(sizeof(Code));
code->bPushd1 = code->bPushd2 = code->bPushd3 = code->bPushd4 = 0x68;
code->bCallOff = 0xE8;
code->bRetn = 0xC2;
code->wRetSize = sizeof(DWORD);
code->dwType = (DWORD)uType;
code->dwCaption = (DWORD)lpCaption;
code->dwText = (DWORD)lpText;
code->dwHWND = (DWORD)hWnd;
DWORD ptr;
ptr = (DWORD) GetProcAddress(LoadLibrary("user32.dll"), "MessageBoxA");
code->dwAddress = ptr - (DWORD)&code->bRetn;
}
~ShowMessageBox() {
executableHeap.free(code);
}
DWORD conquerWorld() {
HANDLE hThread;
DWORD retn;
hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)code, 0, 0, 0);
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &retn);
CloseHandle(hThread);
return retn;
}
};
ShowMessageBox::ExecutableHeap ShowMessageBox::executableHeap;
int main() {
clog << "before." << endl;
ShowMessageBox smb(0, "Małą czarną?", "zue zuo", MB_ICONWARNING | MB_YESNO);
DWORD btn = smb.conquerWorld();
cout << (btn == IDYES ? "Yes." : btn == IDNO ? "No." : "WTF?") << endl;
clog << "after." << endl;
}
Buduje? 'Buduje'. Odpala w innym wątku? Odpala. Za ewentualne szkody nie odpowiedam... szkody moralne oczywiście.
Funkcjonuje to tak - na oddzielnej stercie z prawami do wykonywania tworzy blok i składa do kupy stałe + argumenty w jeden spójny kod z zakodowanymi wartościami zmiennych i bezpośrednim wywołaniem MessageBoksa prosto z user32 (takie rzeczy to tylko w runtime...). Struktura Code, a raczej pary jej składowych, to po prostu reprezentacja kolejnych instrukcji kodu maszynowego. conquerWorld() niestety nie robi tego co powinno (brak czasu i umiejętności) a jedynie tworzy nowy wątek ze zbudowanego kodu, czeka na jego zakończenie i zwraca wynik MessageBoksa. Cała filozofia. Jak widać dać się da, da się nawet napisać to w bardzo 'oryginalnym' stylu (zważywszy, że na upartego to samo można w kilku-kilkunastu linijkach zrobić).
A poważnie to dynamiczne budowanie kodu to podstawa JIT używanego powszechnie w maszynach wirtualnych. Oczywiście protectory i inne poważniejsze twory zabezpieczające pliki wykonywalne także często budują kod podczas wykonywania - chociażby takie przekierowanie importów.
Dobra, pobawiłem się to wracam nudzić się dalej.
Dzięki wielkie :) .
Ja też dziękuję, zawsze chciałem sobie do interpretera JIT dodać, a zacząć było najtrudniej. Mam co psuć, będę sobie psuł. Ciekawe, ile "nieprawidłowych operacji" minie, zanim będzie wszystko działać jak należy ;)