Šifrování funkce za běhu programu
Celá funkce funguje velice jednoduše. Nejprve načteme počáteční adresu procedury nebo funkce, kterou chceme zašifrovat. Paměť ve které je funkce, kterou chceme zašifrovat je chráněna proti zápisu – musíme tedy nejprve ochranu paměti odstranit pomocí funkce VirtualProtect(Počáteční adresa, délka, nová ochrana, stará ochrana). Abychom získali délku funkce, musíme její konec nějakým způsobem označit. V uvedeném kódu jsem použil jako označení konce funkce textový řetězec „end.“ vložený přímo do kódu aplikace. Tento řetězec stačí jen najít a tam kde začíná je konec kódu funkce. Po odečtení adresy konce a začátku dostáváme délku kódu funkce. Můžeme tedy zavolat API VirtualProtect. Pokud funkce proběhne v pořádku vrátí 1, jinak 0. Nyní můžeme paměť funkce upravovat jak chceme. Každý byte funkce je xorován s konstantou 10. Dešifrovací rutina bude vypadat totožně díky šifrování za pomocí operátoru XOR.
begin
// zde je libovolný kód funkce, který
// má být zašifrován
Exit; // pokud z funkce nevyskočíme, procesor zpracuje string "end."
asm
db 'end.' // označení konce funkce
end;
end;
procedure ZasifrujKod ();
label
Nalezen_Konec, Najit_Konec_Smycka, Zasifrovano_Konec,
Zasifruj_Smycka;
var
dwOldProtect: DWORD;
begin
asm
lea eax, UlozObrazek // do eax načteme adresu začátku funkce UlozObrazek
mov ebx, eax // do ebx uložíme začátek funkce UlozObrazek
Najit_Konec_Smycka:
mov ecx, dword ptr[ebx] // do ecx vložíme dword na adrese ebx
cmp ecx, 778333797 // ecx porovnáme s 778333797 = pozpátku v ASCII "end."
je Nalezen_Konec // pokud byl nalezen řetězec "end." ukončíme jeho hledání
inc ebx // pokud ne, zvětšíme hodnotu ebx o 1
jmp Najit_Konec_Smycka // a pokračujeme ve smyčce
Nalezen_Konec:
Pushad // uděláme zálohu všech registrů
push [dwOldProtect] // ukazatel na proměnnou dwOldProtect
push PAGE_EXECUTE_READWRITE // konstanta pro nastavení práva zápisu paměti
sub ebx, eax // vypočítáme délku kódu
push ebx // délka kódu funkce UlozObrazek
push eax // adresa začátku funkce UlozObrazek
call VirtualProtect // voláme API VirtualProtect
test eax, eax // je výsledek funkce 0?
je Zasifrovano_Konec // pokud ano, došlo k chybě a šifrování provádět nebudeme
popad // vyvoláme zpět zálohované registry
Zasifruj_Smycka:
cmp ebx, eax // porovnáme adresu právě šifrovaného bytu s adresou konce
je Zasifrovano_Konec // pokud se shodují, tak jsme na konci a šifrování ukončíme
xor byte ptr[eax], 10 // xorujeme byte na adrese eax
inc eax // přičteme k eax 1
jmp Zasifruj_Smycka // skočíme zpět
Zasifrovano_Konec:
end;
end;