文字列が関数だ

#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を作ってみようかと思って、考えてた時のメモでした。