背景
LUA刚流行起来的时候,想学习一下LUA。就找了一款使用LUA脚本引擎的游戏玩。希望从中了解LUA的使用
结果
熟悉了LUA的同时也熟悉了这款游戏。
准备工作
使用detoured withdll注入LUAK.dll。LUAK.dll用于管理LUA环境
procedure PROCESS_ATTACH(); stdcall
begin// Msg_hwd := TMsg_hwd.Create;HookAPI_init;
end;
拦截了 函数:lua_pushstring lua_setfield lua_pushcclosure luaL_newstate luaL_openlibs luaL_loadbuffer lua_pushlstring lua_tointeger lua_pushinteger lua_pushboolean lua_toboolean lua_createtable lua_resume lua_pushnumber lua_settop lua_tolstring lua_settable lua_pushlightuserdata lua_newthread lua_pushnil lua_tonumber luaL_checknumber lua_yield lua_type lua_typename lua_gettable lua_isstring lua_pcall lua_getfield luaopen_table luaopen_math luaopen_string luaopen_base lua_close lua_touserdata
procedure HookAPI_init;
vardwProtect, temp, k: cardinal;
begin//writelogfs('HookAPI_init');LoadLuaLib('Lua5.dll');writelogfs('LoadLuaLib');LUA_HMODULE := fLibHandle;@Oldlua_pushstringFunction := GetProcAddress(LUA_HMODULE, 'lua_pushstring');if assigned(Oldlua_pushstringFunction) thenOldlua_pushstringAddress := DWORD(@Oldlua_pushstringFunction);Spylua_pushstringAddress := DWORD(@Spylua_pushstring);VirtualProtect(@Oldlua_pushstringFunction, 6, PAGE_EXECUTE_READWRITE, @dwProtect);move(PChar(Oldlua_pushstringAddress)[0], tmpBuff_lua_pushstring[0], 6);PChar(Oldlua_pushstringAddress)^ := #$FF;PChar(Oldlua_pushstringAddress + 1)^ := #$25;PInteger(Oldlua_pushstringAddress + 2)^ := DWORD(@Spylua_pushstringAddress);VirtualProtect(@Oldlua_pushstringFunction, 6, dwProtect, @temp);//@Oldlua_setfieldFunction := GetProcAddress(LUA_HMODULE, 'lua_setfield');if assigned(Oldlua_setfieldFunction) thenOldlua_setfieldAddress := DWORD(@Oldlua_setfieldFunction);Spylua_setfieldAddress := DWORD(@Spylua_setfield);VirtualProtect(@Oldlua_setfieldFunction, 6, PAGE_EXECUTE_READWRITE, @dwProtect);move(PChar(Oldlua_setfieldAddress)[0], tmpBuff_lua_setfield[0], 6);PChar(Oldlua_setfieldAddress)^ := #$FF;PChar(Oldlua_setfieldAddress + 1)^ := #$25;PInteger(Oldlua_setfieldAddress + 2)^ := DWORD(@Spylua_setfieldAddress);VirtualProtect(@Oldlua_setfieldFunction, 6, dwProtect, @temp);@Oldlua_pushcclosureFunction := GetProcAddress(LUA_HMODULE, 'lua_pushcclosure');if assigned(Oldlua_pushcclosureFunction) thenOldlua_pushcclosureAddress := DWORD(@Oldlua_pushcclosureFunction);Spylua_pushcclosureAddress := DWORD(@Spylua_pushcclosure);VirtualProtect(@Oldlua_pushcclosureFunction, 6, PAGE_EXECUTE_READWRITE, @dwProtect);move(PChar(Oldlua_pushcclosureAddress)[0], tmpBuff_lua_pushcclosure[0], 6);PChar(Oldlua_pushcclosureAddress)^ := #$FF;PChar(Oldlua_pushcclosureAddress + 1)^ := #$25;PInteger(Oldlua_pushcclosureAddress + 2)^ := DWORD(@Spylua_pushcclosureAddress);VirtualProtect(@Oldlua_pushcclosureFunction, 6, dwProtect, @temp);//@OldluaL_newstateFunction := GetProcAddress(LUA_HMODULE, 'luaL_newstate');if assigned(OldluaL_newstateFunction) thenOldluaL_newstateAddress := DWORD(@OldluaL_newstateFunction);SpyluaL_newstateAddress := DWORD(@SpyluaL_newstate);VirtualProtect(@OldluaL_newstateFunction, 6, PAGE_EXECUTE_READWRITE, @dwProtect);move(PChar(OldluaL_newstateAddress)[0], tmpBuff_luaL_newstate[0], 6);PChar(OldluaL_newstateAddress)^ := #$FF;PChar(OldluaL_newstateAddress + 1)^ := #$25;PInteger(OldluaL_newstateAddress + 2)^ := DWORD(@SpyluaL_newstateAddress);VirtualProtect(@OldluaL_newstateFunction, 6, dwProtect, @temp);@OldluaL_openlibsFunction := GetProcAddress(LUA_HMODULE, 'luaL_openlibs');if assigned(OldluaL_openlibsFunction) thenOldluaL_openlibsAddress := DWORD(@OldluaL_openlibsFunction);SpyluaL_openlibsAddress := DWORD(@SpyluaL_openlibs);VirtualProtect(@OldluaL_openlibsFunction, 6, PAGE_EXECUTE_READWRITE, @dwProtect);move(PChar(OldluaL_openlibsAddress)[0], tmpBuff_luaL_openlibs[0], 6);PChar(OldluaL_openlibsAddress)^ := #$FF;PChar(OldluaL_openlibsAddress + 1)^ := #$25;PInteger(OldluaL_openlibsAddress + 2)^ := DWORD(@SpyluaL_openlibsAddress);VirtualProtect(@OldluaL_openlibsFunction, 6, dwProtect, @temp);@OldluaL_loadbufferFunction := GetProcAddress(LUA_HMODULE, 'luaL_loadbuffer');if assigned(OldluaL_loadbufferFunction) thenOldluaL_loadbufferAddress := DWORD(@OldluaL_loadbufferFunction);SpyluaL_loadbufferAddress := DWORD(@SpyluaL_loadbuffer);VirtualProtect(@OldluaL_loadbufferFunction, 6, PAGE_EXECUTE_READWRITE, @dwProtect);move(PChar(OldluaL_loadbufferAddress)[0], tmpBuff_luaL_loadbuffer[0], 6);PChar(OldluaL_loadbufferAddress)^ := #$FF;PChar(OldluaL_loadbufferAddress + 1)^ := #$25;PInteger(OldluaL_loadbufferAddress + 2)^ := DWORD(@SpyluaL_loadbufferAddress);VirtualProtect(@OldluaL_loadbufferFunction, 6, dwProtect, @temp);
数据分析
在luaL_loadbuffer 中保存LUA代码到文件中,便于以后的分析。
if trim(name) = '' thenbeginSpyluaL_loadstring_count := SpyluaL_loadstring_count + 1;save_fn := Logpath + 'loadbuffer_' + inttostr(SpyluaL_loadstring_count) + '.lua';endelsebeginsave_fn := Logpath + stringreplace(name, ':', '_', [rfReplaceAll]) + inttostr(sz);end;ForceDirectories(ExtractFilePath(save_fn));ms := TMemoryStream.Create;ms.Write(buff[0], sz);ms.Position := 0;ms.SaveToFile(save_fn);FreeAndNil(ms);sl := TStringList.Create;sl.Add('L=' + inttostr(integer(L)));sl.SaveToFile(save_fn + '.txt');FreeAndNil(sl);last_sz := sz;last_ch1 := buff[0];last_ch2 := buff[1];
也可以在这里修改LUA代码,例如
setlength(lua, sz);Move(buff[0], lua[1], sz);if pos('gf_SetPlayerInvincible(nTime)', lua) > 0 thenbeginfun_name := 'luaL_loadbuffer';lua := lua + #13#10 + ' gf_SetPlayerInvincible(10000) ';result := OldluaL_loadbufferFunction(L, pchar(lua), length(lua), name);lua := stringreplace(lua, 'return szCIP;', ' gf_SetPlayerInvincible(10000);'#13#10'return szCIP;', [rfIgnoreCase]);writelogfs(fun_name + ' gf_SetPlayerInvincible');endelsebeginresult := OldluaL_loadbufferFunction(L, buff, sz, name);end;lua := '';
LUA源码记录到文件中之后,可以先看看文件中的LUA源码进行学习。俺的经验是先看文件尺寸,选大的。
然后就可以从这些LUA的源码中学习LUA的源码,在学习LUA的源码同时也可以熟悉这个游戏
随着学习LUA代码,发现了这个游戏有很多新手对话任务。这些任务只要执行
idx=8101;
ClientAcceptTask(idx);
ClientCompleteTask(idx);
就可以领取并完成任务,这样就可以获得经验并升级。
工具
任务列表,从lua源码中提取的