在收集LUA资料进行学习时,其中有个叫LuaDec的,能把LUA编译出来的代码解回去(逆回脚本内容),官方网站是:
http://luadec.luaforge.net/
它最后支持LUA5.0版本的代码,不过LUA也是开源的,个人可修改源码,这很难应对所有版本。
LuaDec的示例,只是用luaL_loadfile把脚本文件载入,然后就进行解码了,没有在LUA中运作时,LUA执行脚本的哪部分内容。没有这样的例子。
本人不会写文章,直接贴源码及分析时的经验。
主要HOOK上luaV_execute以及luaV_execute函数里边的luaD_poscall地方
如果是HOOK别人的程序,需要注意对LUA源码进行修改,达到和别人的LUA进行同步。
我接触过2~3个程序,目前发现其比较相同处
1,枚举型OpCode的指令顺序要对应
2,lua_TObject的结构大小,以及其成员value,tt的上下位置
3,LUA5.1版本时,Proto结构的变化
4,LUA5.1版本是,LClosure的结构变化
LUA源码好多宏,好多union类型,看着头疼,最后是用OD跟踪看内存,再拿源码对比得出些经验的
代码:
// TestLuaDec.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "windows.h" #include "stdlib.h" DWORD dwSubLuaRet = 0; DWORD dwLuaRet = 0; BOOL bMainLuaStart = FALSE; lua_State* luaHookHandle = NULL; DWORD fnluaV_execute = NULL; DWORD fnluaD_precall = NULL; void hookluaEx() { __try{ char* code = lua_Dec(luaHookHandle, -1); if (code) { printf("主函数开始\n"); printf(code); printf("主函数结束\n\n"); free(code); } }__except (EXCEPTION_EXECUTE_HANDLER) { printf("lua fail"); return; } } __declspec(naked) void hooklua(DWORD lua) { __asm { push ebp mov ebp, esp push eax mov eax, lua mov luaHookHandle, eax pop eax push lua call fnluaV_execute mov dwLuaRet, eax call hookluaEx add esp, 4 mov eax,dwLuaRet pop ebp retn } } void hookSubluaEx() { __try{ char* code = lua_DecSub(luaHookHandle, -1); if (code) { printf("子函数开始\n"); printf(code); printf("子函数结束\n\n"); free(code); } }__except (EXCEPTION_EXECUTE_HANDLER) { printf("lua fail"); return; } } __declspec(naked) void hookSublua(DWORD lua, DWORD lua2) { __asm { push ebp mov ebp, esp push lua2 push lua call fnluaD_precall mov dwSubLuaRet, eax call hookSubluaEx add esp, 8 mov eax,dwSubLuaRet pop ebp retn } } void HookLua() { HMODULE ImageBase = GetModuleHandle(NULL); PIMAGE_DOS_HEADER dos_stub = (PIMAGE_DOS_HEADER)ImageBase; PIMAGE_NT_HEADERS PEHead = (PIMAGE_NT_HEADERS)((DWORD)ImageBase + dos_stub->e_lfanew); DWORD f_luaV_execute = 0x0000E13D; BOOL b_luaV_execute = FALSE; DWORD f_luaD_precall = 0xFED8BD83; BOOL b_luaD_precall = FALSE; DWORD i = 0; DWORD OldProtect, tOld; for (int NOS=0; NOS<PEHead->FileHeader.NumberOfSections; NOS++) { PIMAGE_SECTION_HEADER pSecHeader = (PIMAGE_SECTION_HEADER)((DWORD)PEHead + NOS * sizeof(IMAGE_SECTION_HEADER)+sizeof(IMAGE_NT_HEADERS)); if (IMAGE_SCN_CNT_CODE & pSecHeader->Characteristics) { char* pFile = (char*)((DWORD)ImageBase+pSecHeader->VirtualAddress); for (i=0; i<pSecHeader->SizeOfRawData-0x10; i++) { if (b_luaD_precall && b_luaD_precall) break; if (b_luaV_execute == FALSE && !memcmp(&pFile[i], &f_luaV_execute, 4)) { if (*(PBYTE)(pFile+i+0x32) == 0xE8) { b_luaV_execute = TRUE; DWORD t = (DWORD)ImageBase + i + pSecHeader->VirtualAddress + 0x32; VirtualProtect((void*)t, 5, PAGE_EXECUTE_READWRITE, &OldProtect); fnluaV_execute = t + 5 + *(PDWORD)(t+1); (*(PDWORD)(t+1)) = (DWORD)hooklua - t - 5; VirtualProtect((void*)i, 5, OldProtect, &tOld); } } if (b_luaD_precall == FALSE && !memcmp(&pFile[i], &f_luaD_precall, 4)) { if (*(PBYTE)(pFile+i-0x0E) == 0xE8) { b_luaD_precall = TRUE; DWORD t = (DWORD)ImageBase + i + pSecHeader->VirtualAddress - 0x0E; VirtualProtect((void*)t, 5, PAGE_EXECUTE_READWRITE, &OldProtect); fnluaD_precall = t + 5 + *(PDWORD)(t+1); (*(PDWORD)(t+1)) = (DWORD)hookSublua - t - 5; VirtualProtect((void*)i, 5, OldProtect, &tOld); } } } } } } int main(int argc, char* argv[]) { #ifdef _DEBUG //代码特征在DEBUG版本有效 HookLua(); #endif lua_State* L; L=lua_open(); luaopen_base(L); luaopen_io(L); luaopen_math(L); luaopen_string(L); luaopen_table(L); lua_dofile(L, "test.lua"); system("pause"); return 0; }