首页
社区
课程
招聘
[看雪CTF2016]第二题分析
发表于: 2016-11-5 16:29 4478

[看雪CTF2016]第二题分析

2016-11-5 16:29
4478
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

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 1355
活跃值: (339)
能力值: ( LV13,RANK:920 )
在线值:
发帖
回帖
粉丝
2
对称算法采用了RC6
2016-11-6 12:13
0
雪    币: 11
活跃值: (199)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
求教lua的静态lib怎么制作sig,制作总是不成功
2016-11-7 11:45
0
雪    币: 134
活跃值: (11)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
哈哈,我也做了sig,而且是从5.1做到5.3.3,不过好像就识别出来一个...也忘了是哪个版本了,后面我就人肉识别了
2016-11-7 12:24
0
雪    币: 11
活跃值: (199)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
怎么做的,分享一下呀
2016-11-7 12:30
0
雪    币: 134
活跃值: (11)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
编译lua源码生成.lib,然后就用ida的flirt工具做sig就行了,论坛里有人发过一个批处理工具,你搜下,很方便的
2016-11-7 12:39
0
雪    币: 11
活跃值: (199)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
谢谢哈,我找找
2016-11-7 12:42
0
游客
登录 | 注册 方可回帖
返回
//