背景
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;
var
dwProtect, 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) then
Oldlua_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) then
Oldlua_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) then
Oldlua_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) then
OldluaL_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) then
OldluaL_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) then
OldluaL_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) = '' then
begin
SpyluaL_loadstring_count := SpyluaL_loadstring_count + 1;
save_fn := Logpath + 'loadbuffer_' + inttostr(SpyluaL_loadstring_count) + '.lua';
end
else
begin
save_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 then
begin
fun_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');
end
else
begin
result := OldluaL_loadbufferFunction(L, buff, sz, name);
end;
lua := '';
LUA源码记录到文件中之后,可以先看看文件中的LUA源码进行学习。俺的经验是先看文件尺寸,选大的。
然后就可以从这些LUA的源码中学习LUA的源码,在学习LUA的源码同时也可以熟悉这个游戏
随着学习LUA代码,发现了这个游戏有很多新手对话任务。这些任务只要执行
idx=8101;
ClientAcceptTask(idx);
ClientCompleteTask(idx);
就可以领取并完成任务,这样就可以获得经验并升级。
工具
任务列表,从lua源码中提取的