1、直接运行起来,再用OD附加
在此处luajit加载并调用main函数
004021C7 E8 64FE0000 call CrackMe.00412030 ; luaL_newstate 004021CC 8BF0 mov esi,eax 004021CE 56 push esi 004021CF E8 9C000100 call CrackMe.00412270 ; luaL_openlibs(lua_State *L) 004021D4 53 push ebx 004021D5 68 75020000 push 0x275 004021DA 8D4424 3C lea eax,dword ptr ss:[esp+0x3C] 004021DE 50 push eax 004021DF 56 push esi 004021E0 E8 5B040100 call CrackMe.00412640 ; int luaL_loadbuffer(lua_State*L,const char*buff,size_t size,const char*name 004021E5 53 push ebx 004021E6 56 push esi 004021E7 E8 C41B0100 call CrackMe.00413DB0 004021EC 68 883E4800 push CrackMe.00483E88 ; ASCII "main" 004021F1 68 EED8FFFF push -0x2712 004021F6 56 push esi 004021F7 E8 84130100 call CrackMe.00413580 ; void (lua_getfield) (lua_State *L, int idx, const char *k); 004021FC 57 push edi 004021FD 56 push esi 004021FE E8 DD0E0100 call CrackMe.004130E0 ; lua_pushstring 00402203 6A 01 push 0x1 00402205 56 push esi 00402206 E8 A51B0100 call CrackMe.00413DB0 ; lua_call
2、在luaL_loadbuffer出下断开dump下luajit的bytecode
使用luajit-decomp进行反编译,注意:可以此处是LuaJIT-2.1.0-beta3,需编译替换luajit-decomp中对应的文件
在IDA中字符串列表中搜索lua可以知道lua和luajit的版本。注意:由于有反调试,先运行程序在用OD附加然后dump
Address Length Type String ------- ------ ---- ------ .text:00471CFC 0000002E C PANIC: unprotected error in call to Lua API ( .text:00473EA0 00000028 C 'module' not called from a Lua function .text:00473F40 00000026 C .\?.lua;!\lua\?.lua;!\lua\?\init.lua; .text:00472097 00000016 C Lua function expected .text:00473378 00000013 C LuaJIT 2.1.0-beta3 .text:00473D1C 0000000D C luaJIT_BC_%s .text:00473590 0000000C C lua_debug> .text:00473D2C 0000000B C luaopen_%s .text:00473F34 0000000A C LUA_CPATH .text:00473F74 0000000A C LUA_NOENV .text:00473F68 00000009 C LUA_PATH .text:00474240 00000008 C Lua 5.1
dump下luajit的bytecode:
-- BYTECODE -- lua.bytes:0-0 function someFunc0() var_0_4 = INPUT_VAR_0_ var_0_5 = INPUT_VAR_1_ var_0_6 = INPUT_VAR_1_ var_0_3 = string.sub(var_0_4, var_0_5, var_0_6) --var_0_3 REPLACE-REPLACE string.byte(var_0_3) end -- BYTECODE -- lua.bytes:0-0 function someFunc1() var_1_2 = INPUT_VAR_0_ var_1_1 = string.len(var_1_2) if var_1_1 ~= 0 then --jump to 0009 (if previous if statement is false) --0009 JMP-JMP var_1_1 = 0 --var_1_1 NUMBER-NUMBER return var_1_1 --location 0009--0009 LOCATION-LOCATION var_1_3 = INPUT_VAR_0_ var_1_4 = 1 --var_1_4 NUMBER-NUMBER var_1_2 = by(var_1_3, var_1_4) var_1_3 = 112 --var_1_3 NUMBER-NUMBER var_1_1 = bit.bxor(var_1_2, var_1_3) var_1_4 = INPUT_VAR_0_ var_1_5 = 2 --var_1_5 NUMBER-NUMBER var_1_3 = by(var_1_4, var_1_5) var_1_4 = 101 --var_1_4 NUMBER-NUMBER var_1_2 = bit.bxor(var_1_3, var_1_4) var_1_5 = INPUT_VAR_0_ var_1_6 = 3 --var_1_6 NUMBER-NUMBER var_1_4 = by(var_1_5, var_1_6) var_1_5 = 100 --var_1_5 NUMBER-NUMBER var_1_3 = bit.bxor(var_1_4, var_1_5) var_1_6 = INPUT_VAR_0_ var_1_7 = 4 --var_1_7 NUMBER-NUMBER var_1_5 = by(var_1_6, var_1_7) var_1_6 = 105 --var_1_6 NUMBER-NUMBER var_1_4 = bit.bxor(var_1_5, var_1_6) var_1_7 = INPUT_VAR_0_ var_1_8 = 5 --var_1_8 NUMBER-NUMBER var_1_6 = by(var_1_7, var_1_8) var_1_7 = 121 --var_1_7 NUMBER-NUMBER var_1_5 = bit.bxor(var_1_6, var_1_7) var_1_8 = INPUT_VAR_0_ var_1_9 = 6 --var_1_9 NUMBER-NUMBER var_1_7 = by(var_1_8, var_1_9) var_1_8 = 49 --var_1_8 NUMBER-NUMBER var_1_6 = bit.bxor(var_1_7, var_1_8) var_1_9 = INPUT_VAR_0_ var_1_10 = 7 --var_1_10 NUMBER-NUMBER var_1_8 = by(var_1_9, var_1_10) var_1_9 = 50 --var_1_9 NUMBER-NUMBER var_1_7 = bit.bxor(var_1_8, var_1_9) var_1_10 = INPUT_VAR_0_ var_1_11 = 8 --var_1_11 NUMBER-NUMBER var_1_9 = by(var_1_10, var_1_11) var_1_10 = 51 --var_1_10 NUMBER-NUMBER var_1_8 = bit.bxor(var_1_9, var_1_10) var_1_11 = INPUT_VAR_0_ var_1_12 = 9 --var_1_12 NUMBER-NUMBER var_1_10 = by(var_1_11, var_1_12) var_1_11 = 52 --var_1_11 NUMBER-NUMBER var_1_9 = bit.bxor(var_1_10, var_1_11) var_1_12 = INPUT_VAR_0_ var_1_13 = 10 --var_1_13 NUMBER-NUMBER var_1_11 = by(var_1_12, var_1_13) var_1_12 = 53 --var_1_12 NUMBER-NUMBER var_1_10 = bit.bxor(var_1_11, var_1_12) var_1_13 = INPUT_VAR_0_ var_1_14 = 11 --var_1_14 NUMBER-NUMBER var_1_12 = by(var_1_13, var_1_14) var_1_13 = 54 --var_1_13 NUMBER-NUMBER var_1_11 = bit.bxor(var_1_12, var_1_13) var_1_14 = INPUT_VAR_0_ var_1_15 = 12 --var_1_15 NUMBER-NUMBER var_1_13 = by(var_1_14, var_1_15) var_1_14 = 55 --var_1_14 NUMBER-NUMBER var_1_12 = bit.bxor(var_1_13, var_1_14) var_1_13 = var_1_1 var_1_14 = var_1_2 var_1_15 = var_1_3 var_1_16 = var_1_4 var_1_17 = var_1_5 var_1_18 = var_1_6 var_1_19 = var_1_7 var_1_20 = var_1_8 var_1_21 = var_1_9 var_1_22 = var_1_10 var_1_23 = var_1_11 var_1_24 = var_1_12 return var_1_13, var_1_14, var_1_15, var_1_16, var_1_17, var_1_18, var_1_19, var_1_20, var_1_21, var_1_22, var_1_23, var_1_24 end -- BYTECODE -- lua.bytes:0-0 function someFunc2() var_2_1 = "bit" --var_2_1 STRING-STRING require(var_2_1) local randomFunction0 = function() end -- starts at lua.bytes:0 by = randomFunction0 local randomFunction1 = function() end -- starts at lua.bytes:0 main = randomFunction1 return end
可以看出
someFunc0函数截取字符串指定位置的字符 并转换成byte
someFunc1函数对字符串调用someFunc0函数每个字符截取 并 xor
someFunc2中可以看出 by = randomFunction0 应该就是 by = someFunc0, main = randomFunction1 应该就是 main = someFunc1
3、调用完lua中的main函数后,从lua栈中依次取出每个字符加密后的byte, 然后再次进行 xor
0040222C 55 push ebp 0040222D 6A F4 push -0xC 0040222F 56 push esi 00402230 E8 AB0A0100 call CrackMe.00412CE0 ; lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum); 00402235 8BF8 mov edi,eax 00402237 6A F5 push -0xB 00402239 56 push esi 0040223A 83F7 05 xor edi,0x5 0040223D E8 9E0A0100 call CrackMe.00412CE0 00402242 8BD8 mov ebx,eax 00402244 6A F6 push -0xA 00402246 56 push esi 00402247 83F3 12 xor ebx,0x12 0040224A E8 910A0100 call CrackMe.00412CE0 0040224F 8BE8 mov ebp,eax 00402251 6A F7 push -0x9 00402253 56 push esi 00402254 83F5 0A xor ebp,0xA 00402257 E8 840A0100 call CrackMe.00412CE0 0040225C 83F0 29 xor eax,0x29 0040225F 6A F8 push -0x8 00402261 56 push esi 00402262 894424 58 mov dword ptr ss:[esp+0x58],eax 00402266 E8 750A0100 call CrackMe.00412CE0 0040226B 83F0 42 xor eax,0x42 0040226E 6A F9 push -0x7 00402270 56 push esi 00402271 894424 48 mov dword ptr ss:[esp+0x48],eax 00402275 E8 660A0100 call CrackMe.00412CE0 0040227A 83F0 41 xor eax,0x41 0040227D 6A FA push -0x6 0040227F 56 push esi 00402280 894424 60 mov dword ptr ss:[esp+0x60],eax 00402284 E8 570A0100 call CrackMe.00412CE0 00402289 83F0 75 xor eax,0x75 0040228C 6A FB push -0x5 0040228E 56 push esi 0040228F 894424 60 mov dword ptr ss:[esp+0x60],eax 00402293 E8 480A0100 call CrackMe.00412CE0 00402298 83C4 40 add esp,0x40 0040229B 83F0 61 xor eax,0x61 0040229E 6A FC push -0x4 004022A0 56 push esi 004022A1 894424 18 mov dword ptr ss:[esp+0x18],eax 004022A5 E8 360A0100 call CrackMe.00412CE0 004022AA 83F0 35 xor eax,0x35 004022AD 6A FD push -0x3 004022AF 56 push esi 004022B0 894424 24 mov dword ptr ss:[esp+0x24],eax 004022B4 E8 270A0100 call CrackMe.00412CE0 004022B9 35 83000000 xor eax,0x83 004022BE 6A FE push -0x2 004022C0 56 push esi 004022C1 894424 34 mov dword ptr ss:[esp+0x34],eax 004022C5 E8 160A0100 call CrackMe.00412CE0 004022CA 83F0 55 xor eax,0x55 004022CD 6A FF push -0x1 004022CF 56 push esi 004022D0 894424 44 mov dword ptr ss:[esp+0x44],eax 004022D4 E8 070A0100 call CrackMe.00412CE0 004022D9 35 94000000 xor eax,0x94 004022DE 6A F3 push -0xD 004022E0 56 push esi 004022E1 894424 54 mov dword ptr ss:[esp+0x54],eax 004022E5 E8 26050100 call CrackMe.00412810 004022EA 56 push esi 004022EB E8 80200100 call CrackMe.00414370 ; lua_close
4、最后每个byte和固定的值进行比较
004022F3 83FF 18 cmp edi,0x18 004022F6 75 54 jnz short CrackMe.0040234C 004022F8 83FB 16 cmp ebx,0x16 004022FB 75 4F jnz short CrackMe.0040234C 004022FD 83FD 1E cmp ebp,0x1E 00402300 75 4A jnz short CrackMe.0040234C 00402302 837C24 30 2F cmp dword ptr ss:[esp+0x30],0x2F 00402307 75 43 jnz short CrackMe.0040234C 00402309 837C24 18 48 cmp dword ptr ss:[esp+0x18],0x48 0040230E 75 3C jnz short CrackMe.0040234C 00402310 837C24 28 11 cmp dword ptr ss:[esp+0x28],0x11 00402315 75 35 jnz short CrackMe.0040234C 00402317 837C24 20 21 cmp dword ptr ss:[esp+0x20],0x21 0040231C 75 2E jnz short CrackMe.0040234C 0040231E 837C24 10 37 cmp dword ptr ss:[esp+0x10],0x37 00402323 75 27 jnz short CrackMe.0040234C 00402325 837C24 14 33 cmp dword ptr ss:[esp+0x14],0x33 0040232A 75 20 jnz short CrackMe.0040234C 0040232C 817C24 1C 86000>cmp dword ptr ss:[esp+0x1C],0x86 00402334 75 16 jnz short CrackMe.0040234C 00402336 837C24 24 52 cmp dword ptr ss:[esp+0x24],0x52 0040233B 75 0F jnz short CrackMe.0040234C 0040233D 817C24 2C 94000>cmp dword ptr ss:[esp+0x2C],0x94 00402345 75 05 jnz short CrackMe.0040234C
5、可以提取3处xor的值
lua中main函数对每个字符xor的值
[112,101,100,105,121,49,50,51,52,53,54,55]
0040222C 处对lua输出的每个值进行异或
[0x5,0x12,0xa,0x29,0x42,0x41,0x75,0x61,0x35,0x83,0x55,0x94]
004022F3 处对上面两次异或后的结果和下面的值进行比较
[0x18,0x16,0x1e,0x2f,0x48,0x11,0x21,0x37,0x33,0x86,0x52,0x94]
6、用python进行解码
result = [0x18,0x16,0x1E,0x2F,0x48,0x11,0x21,0x37,0x33,0x86,0x52,0x94] luaxor = [112,101,100,105,121,49,50,51,52,53,54,55] codexor = [0x5,0x12,0xa,0x29,0x42,0x41,0x75,0x61,0x35,0x83,0x55,0x94] code = '' for i in range(len(result)): code += chr(result[i]^luaxor[i]^codexor[i]) print code
结果:maposafe2017