UWSCスクリプトとネイティブコードのキメラ

難読化、といえば、こういう方法もある、という紹介。
ロジックの一部を、ネイティブコードに載せて、わかりにくくする。


とりあえず、0〜9のループを隠蔽してみた。
0〜9にコマンドを割り当てて、ループでない順番に実行させれば、わかりにくいですね。

ループを隠蔽したスクリプト

Complex.uws

OPTION EXPLICIT

IFB GET_UWSC_NAME = "Complex.uws" THEN
	//for(UINT i = 0; i < 10; i++) {
	//	p->data = i;
	//	p->SetEvent(p->hEvent);
	//	p->WaitForSingleObject(p->hEventSync, INFINITE);
	//}
	DIM addr = Asm.Set("VYvsg+wIi0UIiUX8x0X4AAAAAOsJi034g8EBiU34g334CnMqi1X8i0X4iUIQi038i1EIUotF/IsI/9Fq/4tV/ItCDFCLTfyLUQT/0uvHM8CL5V3CBADM")
	DIM paraSize = 20, para = Asm.Alloc(paraSize), i = 0

	IFB addr > 0 AND para > 0 THEN
		i = i + Asm.SetDword(para + i, Asm.GetProcAddress(Asm.hK32, "SetEvent"))
		i = i + Asm.SetDword(para + i, Asm.GetProcAddress(Asm.hK32, "WaitForSingleObject"))
		DEF_DLL CreateEventA(DWORD,BOOL,BOOL,DWORD): DWORD: kernel32
		DIM hEvent = CreateEventA(0, FALSE, FALSE, 0)
		DIM hEventSync = CreateEventA(0, FALSE, FALSE, 0)
		i = i + Asm.SetDword(para + i, hEvent)
		i = i + Asm.SetDword(para + i, hEventSync)
		//Asm.Dump(para, paraSize)

		// UWSC側実行スクリプトを起動する
		THREAD ProcMain(hEvent, hEventSync, para + i)
		// コントロール用ネイティブスレッドを起動する
		//  UWSCのメインスレッドが止まるとサブも止まるみたい
		DIM hThread = Asm.Run(addr, para, i, -1), res = 258
		WHILE res = 258
			res = Asm.WaitForSingleObject(hThread, 10)
		WEND
		Asm.CloseHandle(hThread)

		// 解放
		Asm.Free(para)
		Asm.Free(addr)
		Asm.CloseHandle(hEvent)
		Asm.CloseHandle(hEventSync)
	ENDIF
ENDIF

PROCEDURE ProcMain(hEvent, hEventSync, p)
	DEF_DLL SetEvent(DWORD): bool: kernel32
	DIM para = 0
	WHILE para < 9
		Asm.WaitForSingleObject(hEvent, $FFFFFFFF)
		para = Asm.GetDword(p)
		PRINT "Para:" + para
		SetEvent(hEventSync)
	WEND
FEND


// このAsmモジュールは、GetDword追加型
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

	PUBLIC hK32
	PUBLIC hU32

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

	FUNCTION Set(code)
		DIM dom = CreateOleObj("Microsoft.XMLDOM")
		DIM binMan = dom.createElement("tmp")
		binMan.dataType = "bin.base64"
		binMan.text = code
		DIM i = LENGTH(code), size = i * 3 / 4
		IFB i > 3 THEN
			IF COPY(code, i-1, 1) = "=" THEN size = size - 1
			IF COPY(code, i, 1) = "=" THEN size = size - 1
		ENDIF
		DIM data[size-1], b = binMan.nodeTypedValue
		FOR i = 0 TO size - 1
			data[i] = b[i]
		NEXT

		RESULT = VirtualAlloc(0, size, $1000, $40)
		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


、、、ま、ネイティブコードが書ける人なら、
ネイティブコードで行えば良いんですけどね、、、。
いや、でも、いろいろ面倒だからUWSCを使うわけで、、、。
ま、こんなキメラも作れます、ということ。