1. 先粗略跟一下
找到解密字符串的函数
.text:0041B422 ; BOOL __stdcall decrypt_string(void **ppBuf, unsigned int *pBufSize, int key)
把所有调用该函数的字符串都解密并标注, 发现如下字符串
.rdata:0042DE64 sz_fnGetRegSnToVerify
.rdata:0042DF64 sz_fnCalcUserInputRegSnAfterEnc
.rdata:0042E064 sz_userRegister
.rdata:0042E164 sz_getRegSnAfterCalc
再搜索下字符串, 感觉有点像脚本语言, 找了些字符串google一下, "setmetatable", "istailcall",
出来的是跟lua相关的
2. 去官网下了lua-5.3.3源码
边看lua源码, 边与ida对照, 先识别出了luaL_newstate, 然后再多识别其他一些lua的库函数
(编译lua的静态lib, 制作sig导入ida, 好像只能识别出一小部分库函数)
.text:0041ADC3 call luaL_newstate
定位出了两个函数fnGetRegSnToVerify, fnCalcUserInputRegSnAfterEnc
.text:0041ADE6 push offset sz_fnGetRegSnToVerify ; void *
.text:0041ADEB push eax ; void *
.text:0041ADEC mov [ebp+lpMem], eax
.text:0041ADEF call _memcpy
.text:0041ADF4 movzx eax, ds:byte_42D20C
.text:0041ADFB add esp, 14h
.text:0041ADFE mov ecx, esi
.text:0041AE00 mov [ebp+a2], edi
.text:0041AE03 push eax ; key
.text:0041AE04 lea eax, [ebp+a2]
.text:0041AE07 push eax ; pBufSize
.text:0041AE08 lea eax, [ebp+lpMem]
.text:0041AE0B push eax ; ppBuf
.text:0041AE0C call decrypt_string
.text:0041AE11 test eax, eax
.text:0041AE13 jz short loc_41AE31
.text:0041AE15 push ebx ; n
.text:0041AE16 push offset fnGetRegSnToVerify ; fn
.text:0041AE1B push dword ptr [esi+10h] ; L
.text:0041AE1E call lua_pushcclosure
.text:0041AE23 push [ebp+lpMem] ; name
.text:0041AE26 push dword ptr [esi+10h] ; L
.text:0041AE29 call lua_setglobal
.text:0041AE46 push offset sz_fnCalcUserInputRegSnAfterEnc ; void *
.text:0041AE4B push eax ; void *
.text:0041AE4C mov [ebp+lpMem], eax
.text:0041AE4F call _memcpy
.text:0041AE54 movzx eax, ds:byte_42D210
.text:0041AE5B add esp, 10h
.text:0041AE5E mov ecx, esi
.text:0041AE60 mov [ebp+a2], edi
.text:0041AE63 push eax ; key
.text:0041AE64 lea eax, [ebp+a2]
.text:0041AE67 push eax ; pBufSize
.text:0041AE68 lea eax, [ebp+lpMem]
.text:0041AE6B push eax ; ppBuf
.text:0041AE6C call decrypt_string
.text:0041AE71 test eax, eax
.text:0041AE73 pop edi
.text:0041AE74 jz short loc_41AE92
.text:0041AE76 push ebx ; n
.text:0041AE77 push offset fnCalcUserInputRegSnAfterEnc ; fn
.text:0041AE7C push dword ptr [esi+10h] ; L
.text:0041AE7F call lua_pushcclosure
.text:0041AE84 push [ebp+lpMem] ; name
.text:0041AE87 push dword ptr [esi+10h] ; L
.text:0041AE8A call lua_setglobal
3. 标注出lua库函数后就方便多了
第一次处理sn的地方, encrypt_string是加密, decrypt_string是解密
.text:0041B494 encrypt_sn proc near ; CODE XREF: sub_4017EA+92p
.text:0041B494
.text:0041B494 arg_0 = dword ptr 4
.text:0041B494 arg_4 = dword ptr 8
.text:0041B494
.text:0041B494 movzx eax, ds:byte_42D204
.text:0041B49B push eax
.text:0041B49C push [esp+4+arg_4]
.text:0041B4A0 push [esp+8+arg_0]
.text:0041B4A4 call encrypt_string
加载lua脚本(见lua.bytecode)
.text:0041AF51 push [ebp+a2] ; size_t
.text:0041AF54 push offset sz_lua_bytecode ; void *
.text:0041AF59 push eax ; void *
.text:0041AF5A call _memcpy
.text:0041AF5F movzx eax, ds:byte_42D204
.text:0041AF66 add esp, 0Ch
.text:0041AF69 mov ecx, esi
.text:0041AF6B push eax ; key
.text:0041AF6C lea eax, [ebp+a2]
.text:0041AF6F push eax ; pBufSize
.text:0041AF70 lea eax, [ebp+lpMem]
.text:0041AF73 push eax ; ppBuf
.text:0041AF74 call decrypt_string
.text:0041AF79 push ebx ; mode
.text:0041AF7A push ebx ; name
.text:0041AF7B push [ebp+a2] ; size
.text:0041AF7E push [ebp+lpMem] ; buff
.text:0041AF81 push dword ptr [esi+10h] ; L
.text:0041AF84 call _luaL_loadbufferx
反编译脚本: luadec(https://github.com/viruscamp/luadec)
该lua脚本直接用luadec解不了, 跟进luaU_undump->checkHeader, 发现头部略有改动, 改回来((见lua.luac))就可以用luadec反编译了
.text:00417807 ; LClosure *__cdecl luaU_undump(lua_State *L, Zio *Z, const char *name)
.text:00417807 luaU_undump proc near ; CODE XREF: f_parser+50p
.text:00417841 call checkHeader
反编译结果(见lua.lua)
-- Decompiled using luadec 2.2 rev: for Lua 5.3 from https://github.com/viruscamp/luadec
-- Command line: lua.luac
-- params : ...
-- function num : 0 , upvalues : _ENV
g_strRegSn = " "
g_strRegSnToVerify = ""
userRegister = function(strRegSnIn)
-- function num : 0_0 , upvalues : _ENV
local iRc = -1
g_strRegSn = strRegSnIn
g_strRegSnToVerify = fnGetRegSnToVerify()
g_strRegSn = fnCalcUserInputRegSnAfterEnc(g_strRegSn)
if g_strRegSn == g_strRegSnToVerify then
iRc = 1024
end
g_strRegSnToVerify = ""
return iRc
end
getRegSnAfterCalc = function(strRegSnIn)
-- function num : 0_1 , upvalues : _ENV
return g_strRegSn
end
调用lua脚本中的userRegister函数
.text:0041AFD2 push offset sz_userRegister ; void *
.text:0041AFD7 push eax ; void *
.text:0041AFD8 mov [ebp+ppBuf], eax
.text:0041AFDB call _memcpy
.text:0041AFE0 movzx eax, ds:byte_42D214
.text:0041AFE7 add esp, 18h
.text:0041AFEA mov ecx, esi
.text:0041AFEC mov [ebp+pBufSize], edi
.text:0041AFEF push eax ; key
.text:0041AFF0 lea eax, [ebp+pBufSize]
.text:0041AFF3 push eax ; pBufSize
.text:0041AFF4 lea eax, [ebp+ppBuf]
.text:0041AFF7 push eax ; ppBuf
.text:0041AFF8 call decrypt_string
.text:0041AFFD test eax, eax
.text:0041AFFF jz short loc_41B011
.text:0041B001 push [ebp+ppBuf]
.text:0041B004 push dword ptr [esi+10h]
.text:0041B007 call lua_getglobal
.text:0041B00C pop ecx
.text:0041B00D mov [ebp+var_10], eax
.text:0041B010 pop ecx
.text:0041B011
.text:0041B011 loc_41B011: ; CODE XREF: enc_41AEF1+10Ej
.text:0041B011 cmp [ebp+ppBuf], ebx
.text:0041B014 jz short loc_41B01F
.text:0041B016 push [ebp+ppBuf] ; lpMem
.text:0041B019 call delete
.text:0041B01E pop ecx
.text:0041B01F
.text:0041B01F loc_41B01F: ; CODE XREF: enc_41AEF1+123j
.text:0041B01F cmp [ebp+var_10], 6
.text:0041B023 jnz loc_41B12E
.text:0041B029 mov eax, [ebp+a3]
.text:0041B02C push dword ptr [eax] ; len
.text:0041B02E mov eax, [ebp+arg0]
.text:0041B031 push dword ptr [eax] ; s
.text:0041B033 push dword ptr [esi+10h] ; L
.text:0041B036 call lua_pushlstring
.text:0041B03B push ebx
.text:0041B03C push ebx
.text:0041B03D push ebx
.text:0041B03E push 1
.text:0041B040 push 1
.text:0041B042 push dword ptr [esi+10h]
.text:0041B045 call lua_pcallk
返回结果必须为1024
.text:0041B05E cmp eax, 1
.text:0041B061 pop ecx
.text:0041B062 jnz loc_41B12E
.text:0041B068 push ebx
.text:0041B069 push eax
.text:0041B06A push dword ptr [esi+10h]
.text:0041B06D call lua_tonumberx
.text:0041B072 add esp, 0Ch
.text:0041B075 call __ftol
.text:0041B07A cmp eax, 1024
4. 获取sn
g_strRegSnToVerify为固定的32字节
.text:004019A2 ; int __cdecl fnGetRegSnToVerify(lua_State *L)
.text:004019A2 fnGetRegSnToVerify proc near ; DATA XREF: cls_ctor+87o
.text:004019A2
.text:004019A2 L = dword ptr 4
.text:004019A2
.text:004019A2 push [esp+L] ; L
.text:004019A6 call _lua_gettop
.text:004019AB test eax, eax
.text:004019AD pop ecx
.text:004019AE jnz short loc_4019C3
.text:004019B0 push 20h ; len
.text:004019B2 push offset g_strRegSnToVerify ; s
.text:004019B7 push [esp+8+L] ; L
.text:004019BB call lua_pushlstring
fnCalcUserInputRegSnAfterEnc -> enc_41B270 -> enc_41B147(aes的代码, 看得有点烦)
enc_41B147 -> enc_402B8C -> xor xor_key_42D224
搜索xor_key_42D224的引用, 再往回溯, 发现了跟enc_41B147相对应的解密代码dec_41B287
计算sn: g_strRegSnToVerify -> dec_41B287 -> decrypt_string -> sn
附件:
extracted.zip
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课