// ************** 跟踪xx游戏加密用户名密码过程 ****************************//
1.在发包处向上跟,得到发包加密处.再向上跟踪,得到
00410DB5 > \55 push ebp
00410DB6 . 6A 00 push 0
00410DB8 . 6A 02 push 2 ; 第一个参数 Login.m_szPassword
00410DBA . 56 push esi ; 参数: db [[esi+C]+10]+10
00410DBB . E8 8CE50A00 call <jmp.&Lua5.lua_tolstring> ; get_password
取加密后的密码.再向上跟,测晕死在lua5.dll中.在此函数开始处下断,用WinHex查看内存,发现加密后的密码已经出现. 2.由此判断加密用lua相关. hook lua5.luaL_loadbuffer,将所有的lua文件dump下来.
查看,发现
ui\config\loginpassword.lua
ui\login.lua
等可疑文件,分析,得到结果,
// --------------------------------------
SaveAccountAndPassword=function()
local frame = Station.Lookup("Normal/LoginPassword/WndPassword")
Login.m_szAccount = frame:Lookup("Edit_Account"):GetText()
Login.m_szPassword = frame:Lookup("Edit_Password"):GetPassword()
.........
// --------------------------------------
StepNext=function()
.........
elseif Login.m_StateLeaveFunction == Login.LeavePassword then
LoginPassword.SaveAccountAndPassword()
if Login.m_bRememberAccount and IsUserDataExist() or Login.m_bSelectServer then
Login.RequestLogin(g_tGlue.tLoginString["CONNECTING"], true)
.........
// --------------------------------------
RequestLogin=function(szMsg, bShowError)
.........
if Login.m_szAccount and Login.m_szPassword then
if not Login.m_szServerIP or not Login.m_nServerPort then
LoadUserData(Login.m_szAccount)
end
local szRegionName, szServerName = LoginServerList.GetSelectedServer()
Login.SelectServer(szRegionName, szServerName)
Login.BeginWait(szMsg)
Login_CancelLogin()
Login_SetGatewayAddress(Login.m_szServerIP, Login.m_nServerPort)
Login_BeginLogin(Login.m_szAccount, Login.m_szPassword)
elseif bShowError then
.........
// --------------------------------------
3.再回头分析[1]处的 取用户名密码,得知,
00410D7D > \6A 00 push 0
00410D7F . 6A 01 push 1 ; 第一个参数 Login.m_szAccount
00410D81 . 56 push esi ; 参数: db [[esi+C]]+10
00410D82 . E8 C5E50A00 call <jmp.&Lua5.lua_tolstring> ; getu_user_name
00410D87 . 83C4 0C add esp, 0C
00410DB5 > \55 push ebp
00410DB6 . 6A 00 push 0
00410DB8 . 6A 02 push 2 ; 第二个参数 Login.m_szPassword
00410DBA . 56 push esi ; 参数: db [[esi+C]+10]+10
00410DBB . E8 8CE50A00 call <jmp.&Lua5.lua_tolstring> ; get_password
00410DC0 . 8BE8 mov ebp, eax
,,判断此处便是lua脚本中的RequestLogin函数中的Login_BeginLogin(Login.m_szAccount, Login.m_szPassword).
猜想
lua脚本中的
Login_CancelLogin()
Login_SetGatewayAddress()
Login_BeginLogin()
都是主程序中的函数.
4.对lua乱跟一通后得知,在Lua脚本中出现的常量这符串都会使用Lua5::lua_tolstring函数获取.
5对Lua5::lua_tolstring结尾处下条件断 STRING [EAX] == "Normal"
得到"Normal/LoginPassword/WndPassword"
与lua脚本中的
local frame = Station.Lookup("Normal/LoginPassword/WndPassword")
对应 5.再断Lua5::lua_tolstring入口,得到"Edit_Account" 和 "Edit_Password"
再到lua_tolstring的返回处,跟回上一层,得到一处call reg,是lua的总调用,
0016AA28 8B56 14 mov edx, dword ptr [esi+14]
0016AA2B 8B42 04 mov eax, dword ptr [edx+4]
0016AA2E 8B08 mov ecx, dword ptr [eax]
0016AA30 8B51 10 mov edx, dword ptr [ecx+10]
0016AA33 56 push esi
0016AA34 FFD2 call edx ; *****
即:Login.m_szAccount = frame:Lookup("Edit_Account"):GetText()
Lua对这行脚本会分为多个步骤执行。
a,取 "Edit_Account"
b, 调用 GetText()
c, 对Login.m_szAccount赋值 6.综合上面的分析,在断到local frame = Station.Lookup("Normal/LoginPassword/WndPassword") 之后,
再断Lua5::lua_tolstring入口,在得到"Edit_Password"之后,断
0016AA34 FFD2 call edx
即是Login.m_szPassword = frame:Lookup("Edit_Password"):GetPassword()中的GetPassword().
7.经过[6]的操作,进入GetPassword().
0CF5C200 . 83EC 44 sub esp, 44 ; frame:Lookup("Edit_Password"):GetPassword()
0CF5C203 . A1 2C40FC0C mov eax, dword ptr [CFC402C]
0CF5C208 . 33C4 xor eax, esp
0CF5C20A . 894424 40 mov dword ptr [esp+40], eax
0CF5C20E . 56 push esi
0CF5C20F . 8B7424 4C mov esi, dword ptr [esp+4C]
0CF5C213 . 6A 3F push 3F ; /n = 3F (63.)
0CF5C215 . 8D4424 09 lea eax, dword ptr [esp+9] ; |
0CF5C219 . 6A 00 push 0 ; |c = 00
0CF5C21B . 50 push eax ; |s
0CF5C21C . C64424 10 00 mov byte ptr [esp+10], 0 ; |
0CF5C221 . E8 56EB0400 call <jmp.&MSVCR80.memset> ; \memset
0CF5C226 . 56 push esi
0CF5C227 . E8 70DF0400 call <jmp.&Lua5.lua_gettop>
0CF5C22C . 83C4 10 add esp, 10
0CF5C22F . 83F8 01 cmp eax, 1
0CF5C232 . 74 11 je short 0CF5C245
0CF5C234 . 68 1086FB0C push 0CFB8610 ; ASCII "UI::KWndClassScriptTable::LuaEdit_GetPassword"
0CF5C239 . 68 B20B0000 push 0BB2
0CF5C23E . 68 A0F2FA0C push 0CFAF2A0 ; ASCII "Lua_GetTopIndex(L) == 1"
0CF5C243 . EB 27 jmp short 0CF5C26C
0CF5C245 > 53 push ebx
0CF5C246 . 68 1076FB0C push 0CFB7610 ; ASCII "WndEdit"
0CF5C24B . BB 01000000 mov ebx, 1
0CF5C250 . E8 EBBDFFFF call 0CF58040
0CF5C255 . 83C4 04 add esp, 4
0CF5C258 . 85C0 test eax, eax
0CF5C25A . 5B pop ebx
0CF5C25B . 75 21 jnz short 0CF5C27E
0CF5C25D . 68 1086FB0C push 0CFB8610 ; ASCII "UI::KWndClassScriptTable::LuaEdit_GetPassword"
0CF5C262 . 68 B50B0000 push 0BB5
0CF5C267 . 68 7878FB0C push 0CFB7878 ; ASCII "pWnd"
0CF5C26C > 68 B0E6FA0C push 0CFAE6B0 ; ASCII "KGLOG_PROCESS_ERROR(%s) at line %d in %s",LF
0CF5C271 . 6A 07 push 7
0CF5C273 . FF15 2CE0FA0C call dword ptr [<&Engine_Lua5.KGLogPrintf>] ; Engine_L.KGLogPrintf
0CF5C279 . 83C4 14 add esp, 14
0CF5C27C . EB 0C jmp short 0CF5C28A
0CF5C27E > 8D4C24 04 lea ecx, dword ptr [esp+4]
0CF5C282 . 51 push ecx
0CF5C283 . 8BC8 mov ecx, eax
0CF5C285 . E8 86A80300 call 0CF96B10 ; ***********************encrypt password********************
0CF5C28A > 8D5424 04 lea edx, dword ptr [esp+4]
0CF5C28E . 52 push edx
0CF5C28F . 56 push esi
0CF5C290 . E8 BFDE0400 call <jmp.&Lua5.lua_pushstring>
0CF5C295 . 8B4C24 4C mov ecx, dword ptr [esp+4C]
0CF5C299 . 83C4 08 add esp, 8
0CF5C29C . 5E pop esi
0CF5C29D . 33CC xor ecx, esp
0CF5C29F . B8 01000000 mov eax, 1
0CF5C2A4 . E8 FDDF0400 call 0CFAA2A6
0CF5C2A9 . 83C4 44 add esp, 44
0CF5C2AC . C3 retn
8.分析GetPassword(),得知
0CF5C285 . E8 86A80300 call 0CF96B10
这个call返回了加密后的密码. 9.再对 call 0CF96B10分析,得知
0CF96C37 . 894424 24 mov dword ptr [esp+24], eax
0CF96C3B . 51 push ecx ;
0CF96C3C . 8D4424 28 lea eax, dword ptr [esp+28]
0CF96C40 . 66:895C24 1A mov word ptr [esp+1A], bx
0CF96C45 . E8 76AEFBFF call 0CF51AC0 ; 取单个字符"78787878"
0CF96C4A . C68424 D00000>mov byte ptr [esp+D0], 1
0CF96C52 . 8B5424 24 mov edx, dword ptr [esp+24]
0CF96C56 . 52 push edx ; 组成字符
0CF96C57 . 8D8C24 AC0000>lea ecx, dword ptr [esp+AC]
0CF96C5E . FF15 FCE1FA0C call dword ptr [<&MSVCP80.std::basic_string<char,std::ch>; msvcp80.std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator+=
......
......
0CF96CF5 . 50 push eax
0CF96CF6 . 52 push edx
0CF96CF7 . FF15 3CE0FA0C call dword ptr [<&Engine_Lua5.KG_EDStringToMD5String>] ; Engine_L.KG_EDStringToMD5String
密码是由Engine_L.KG_EDStringToMD5String进行加密,很可能是MD5.
跟进Engine_L.KG_EDStringToMD5String,发现
1000128A |. E8 11080000 call md5_init
10001296 |. E8 35080000 call md5_append
100012A5 |. E8 F6080000 call md5_finish
10.用MD5测试游戏加密后的密码,正确。可逆。
11.
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)