#include <stdio.h> main(){ int x=100, y=200; char *func="\x55\x89\xE5\x83\xEC\x10\x8B\x45\x08\x8B\x00\x89\x45\xFC\x8B\x45\x0C\x8B\x10\x8B\x45\x08\x89\x10\x8B\x45\x0C\x8B\x55\xFC\x89\x10\xC9\xC3"; printf("x:%d, y:%d\n", x,y); ((void (*)(int*,int*))func)(&x, &y); printf("x:%d, y:%d\n", x,y); }
普通にプログラム書いてデバッガ使ってコピーするだけの簡単なお仕事です。
プログラムを書いて、その関数の部分をデバッガで見る。
今回はフリーで高機能なollydbgを使用。
intのポインタを2つ引数として持つある関数を逆アセンブルしてみるとこんな処理。
CPU Disasm Address Hex dump Command Comments 004013C0 /$ 55 PUSH EBP 004013C1 |. 89E5 MOV EBP,ESP 004013C3 |. 83EC 10 SUB ESP,10 004013C6 |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1] 004013C9 |. 8B00 MOV EAX,DWORD PTR DS:[EAX] 004013CB |. 8945 FC MOV DWORD PTR SS:[LOCAL.1],EAX 004013CE |. 8B45 0C MOV EAX,DWORD PTR SS:[ARG.2] 004013D1 |. 8B10 MOV EDX,DWORD PTR DS:[EAX] 004013D3 |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1] 004013D6 |. 8910 MOV DWORD PTR DS:[EAX],EDX 004013D8 |. 8B45 0C MOV EAX,DWORD PTR SS:[ARG.2] 004013DB |. 8B55 FC MOV EDX,DWORD PTR SS:[LOCAL.1] 004013DE |. 8910 MOV DWORD PTR DS:[EAX],EDX 004013E0 |. C9 LEAVE 004013E1 \. C3 RETN
このdump部分を文字にして出力するだけ。Perlならこんなに簡単。
#!/usr/bin/perl while(<DATA>){ my @code = grep /^[0-9A-Fa-f]+$/, split(/\s+/); shift @code; foreach(@code){ s/../\\x$&/g; print; } } __DATA__ CPU Disasm Address Hex dump Command Comments 004013C0 /$ 55 PUSH EBP 004013C1 |. 89E5 MOV EBP,ESP 004013C3 |. 83EC 10 SUB ESP,10 004013C6 |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1] 004013C9 |. 8B00 MOV EAX,DWORD PTR DS:[EAX] 004013CB |. 8945 FC MOV DWORD PTR SS:[LOCAL.1],EAX 004013CE |. 8B45 0C MOV EAX,DWORD PTR SS:[ARG.2] 004013D1 |. 8B10 MOV EDX,DWORD PTR DS:[EAX] 004013D3 |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1] 004013D6 |. 8910 MOV DWORD PTR DS:[EAX],EDX 004013D8 |. 8B45 0C MOV EAX,DWORD PTR SS:[ARG.2] 004013DB |. 8B55 FC MOV EDX,DWORD PTR SS:[LOCAL.1] 004013DE |. 8910 MOV DWORD PTR DS:[EAX],EDX 004013E0 |. C9 LEAVE 004013E1 \. C3 RETN
\x55\x89\xE5\x83\xEC\x10\x8B\x45\x08\x8B\x00\x89\x45\xFC\x8B\x45\x0C\x8B\x10\x8B\x45\x08\x89\x10\x8B\x45\x0C\x8B\x55\xFC\x89\x10\xC9\xC3
後は出力された文字列を関数として扱って書けばOK。
応用としては、コードを動的に実行できるので、関数の処理にパスワードをかけたりとか出来そうです。
標準入力なり引数なりから、パスワードとなる文字列を受け取って、xorで暗号化/復号化すれば、
正しいパスワードなら無事実行できて、間違ってたらエラーが起きます。
スタックの仕様でそう大きなプログラムを埋め込む事はできませんが。
僕はこの辺に詳しくないので、どこまで仕様でやってもいいことなのかとかよくわからないです。
以上、ラクにcrackmeを作ってみようかと思って、考えてた時のメモでした。