UWSCにできないことはない?

先日からフックだのなんだのと考えてた上に、stuncloudさんの構造体に関する扱いを見つけて、、、閃いてしまった、、、。
UWSCでできないと思い込んでいた、ある手法が可能なことを。


DEF_DLLが何回でもできるのも盲点でした。
UWSCで構造体がもうあんまり怖くないmodule | たっぷす庵



とりあえず見て欲しい

実行しても良いですけど、なんてことはありません。
Win32APIのMessageBoxが表示されるだけ。
、、、表示されるだけ、、、このすごさを判ってくれる人、どれだけいるだろう?
もちろん、こんなことしなくてもMessageBoxは表示できる。
そうなんですけどねー。


Asm.uws

OPTION EXPLICIT

IFB GET_UWSC_NAME = "Asm.uws" THEN
	// return (DWORD)p->MessageBox(p->hWnd, &p->text + p->lstrlen(&p->text) + 1, &p->text, p->type);
	DIM addr = Asm.Set("Vot0JAiLTgyLFo1GEFFQUP/Si04Ii1YEjUQwEVBR/9JewgQA")
	DIM paraSize = 64, para = Asm.Alloc(paraSize), i = 0

	IFB addr > 0 AND para > 0 THEN
		i = i + Asm.SetDword(para + i, Asm.GetProcAddress(Asm.hK32, "lstrlenA"))	// p->lstrlen
		i = i + Asm.SetDword(para + i, Asm.GetProcAddress(Asm.hU32, "MessageBoxA"))	// p->MessageBox
		i = i + Asm.SetDword(para + i, 0)	// p->hWnd
		i = i + Asm.SetDword(para + i, 1)	// p->type
		i = i + Asm.SetString(para + i, "苦労の割には")	// p->text
		i = i + 1	// captionとの区切り。Asm.Allocはゼロクリアされている
		i = i + Asm.SetString(para + i, "MessageBoxが出るだけ")
		PRINT Asm.Run(addr, para, i) + " " + i
		//Asm.Dump(para, paraSize)

		// 解放
		Asm.Free(para)
		Asm.Free(addr)
	ENDIF
ENDIF


MODULE Asm
	DEF_DLL GetLastError(): DWORD: kernel32
	DEF_DLL VirtualAlloc(DWORD, DWORD, DWORD, DWORD): DWORD: kernel32
	DEF_DLL VirtualFree(DWORD, DWORD, DWORD): bool: kernel32
	DEF_DLL GetModuleHandleA(string): DWORD: kernel32
	DEF_DLL GetProcAddress(DWORD, string): DWORD: kernel32
	DEF_DLL CreateThread(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD): DWORD: kernel32
	DEF_DLL WaitForSingleObject(DWORD, DWORD): DWORD: kernel32
	DEF_DLL CloseHandle(DWORD): bool: kernel32
	DEF_DLL GetExitCodeThread(DWORD, var DWORD): bool: kernel32
	DEF_DLL CryptStringToBinaryA(string,DWORD,DWORD,var BYTE[],var DWORD,DWORD,var DWORD): bool: crypt32

	PUBLIC hK32
	PUBLIC hU32

	PROCEDURE Asm
		hk32 = GetModuleHandleA("kernel32")
		hU32 = GetModuleHandleA("user32")
	FEND

	FUNCTION Set(code)
		DIM size = 0, flags = 6
		RESULT = FALSE
		IFB CryptStringToBinaryA(code, 0, flags, NULL, size, 0, flags) AND size > 0 THEN
			DIM data[size-1]
			IFB CryptStringToBinaryA(code, 0, flags, data, size, 0, flags) THEN
				RESULT = VirtualAlloc(0, size, $1000, $40)
			ENDIF
		ENDIF
		IF RESULT THEN SetByte(RESULT, data)
	FEND
	FUNCTION Alloc(size)
		RESULT = VirtualAlloc(0, size, $1000, $4)
	FEND
	FUNCTION Free(addr)
		RESULT = VirtualFree(addr, 0, $8000)
	FEND

	// 戻りはtypeによって異なる
	//  type=0   : スレッド終了コード
	//  type=1   : スレッド終了コード取得失敗エラーコード
	//  type=258 : スレッドハンドル
	//  type=他  : その他エラーコード
	FUNCTION Run(addr, para, var type, timeout=$7FFFFFFF)
		DIM hThread = CreateThread(0, 0, addr, para, 0, 0), res = 0
		RESULT = GetLastError()
		type = 258
		IF timeout >= 0 THEN type = WaitForSingleObject(hThread, timeout)
		SELECT type
		CASE 0
			IFB GetExitCodeThread(hThread, res) THEN
				RESULT = res
			ELSE
				type = 1
				RESULT = GetLastError()
			ENDIF
			CloseHandle(hThread)
		CASE 258
			RESULT = hThread
		SELEND
	FEND

	FUNCTION SetByte(p, data[])
		DEF_DLL RtlMoveMemory(DWORD, BYTE[], DWORD): kernel32
		RESULT = LENGTH(data)
		RtlMoveMemory(p, data, RESULT)
	FEND
	FUNCTION SetDword(p, data)
		DEF_DLL RtlMoveMemory(DWORD, var DWORD, DWORD): kernel32
		RESULT = 4
		RtlMoveMemory(p, data, RESULT)
	FEND
	FUNCTION SetString(p, data)
		DEF_DLL RtlMoveMemory(DWORD, string, DWORD): kernel32
		RESULT = LENGTHB(data)
		RtlMoveMemory(p, data, RESULT)
	FEND

	FUNCTION GetDword(p)
		DEF_DLL RtlMoveMemory(var DWORD, DWORD, DWORD): kernel32
		RESULT = 0
		RtlMoveMemory(RESULT, p, 4)
	FEND
	PROCEDURE Dump(addr, size)
		DEF_DLL RtlMoveMemory(BYTE[], DWORD, DWORD): kernel32
		DIM data[size], i, buf = "", bufa = ""
		RtlMoveMemory(data, addr, size)
		FOR i = 0 TO size - 1
			buf = buf + FORMAT(data[i], 3, -1)
			IFB data[i] >= $20 AND data[i] < $7F THEN
				bufa = bufa + CHR(data[i])
			ELSE
				bufa = bufa + "."
			ENDIF
			IFB i MOD 16 = 15 THEN
				PRINT buf + " " + bufa
				buf = ""
				bufa = ""
			ENDIF
		NEXT
		IF LENGTH(buf) THEN PRINT buf + FORMAT(" ", 49 - LENGTH(buf)) + bufa
	FEND
ENDMODULE

MessageBox表示するだけなのに100行オーバーとか。
アホの極み。

解説

Asm.Setしているのは、だいたい以下のネイティブコードをBase64エンコードしたもの。

return (DWORD)p->MessageBox(p->hWnd, &p->text + p->lstrlen(&p->text) + 1, &p->text, p->type);


、、、だめだ、、、自主規制しようと思ったけど、あまりの嬉しさに書いてしまえ!
どうせスクリプトは載せたのだし、スクリプトキディではまだ何もできまい。
ネイティブコードを作るのも簡単じゃなす。


すごいのは、Asm.Run(いやホントにすごいのはUWSC
CreateThreadしちゃってます。
CreateThreadできるってことは、、、関数ポインターがある、ということ。
関数ポインターがある、ということは、、、CallBack処理ができるということ。
SetWindowLongでウインドウのサブクラス化ができるということ。
DLLなしでFUKIDASIをカラフルにできるということ!(まだそれか!)


さらに言うならば、、、他のプロセスにコードインジェクションすることすらできるということ。
お、恐るべしUWSC


ま、当たり前だよねー。
ポインターが使えるんだから、コードが書いてあれば関数ポインター
頭が固かった、ということか。
技術力が少し上がった気がする。
stuncloudさんに乗せられて、FUKIDASI多色化を考えたおかげ。
でも、Win32APIはいつまで持つのだろうか。

追記 20120705

GetDword関数があった方が便利なことが多いので、追加。

追記 20121025

Base64コードに自由に改行・空白を入れられるよう、Set関数をCryptoAPI方式に変更。