首页
社区
课程
招聘
luajit逆向之注入文件
发表于: 2022-3-22 08:32 19764

luajit逆向之注入文件

2022-3-22 08:32
19764

自己制作的一个小工具, 工作场景为某些cocos2dx手游, 虽然lua可以直接拿到lua_state指针注入, 但在某些场景下直接注入文件是更加方便的, 所以自己研究了一下字节码, 笔记是以前写的. 思路很清晰, 自己动手做的话容易犯小错误

Luajit版本2.1.0 beta2
https://luajit.org/download/LuaJIT-2.1.0-beta2.zip
mingw64

010editor中有bt模板, 但是由于版本变化, 指令解析存在问题, 结构解析无问题

示例lua文件代码:

模板信息

可以看到, 在luajit的二进制文件中, proto的顺序是依次往下的嵌套关系, 主函数体在最外层, 也就是倒数第二个

在proto结构中, 存有头信息, 二进制字节码, 常量信息.

模板信息

在头信息中我们要关心的主要有size, complex_constants_count, instructions_count三个字段, 他们的大小由变长数字uleb128描述, 互相转化的方法如下

在我们修改文件的时候需要修正这几条数据.

修改二进制数据, 插入require("inject")语句. 在luajit中, require语句由三条指令构成, 主要是加载require字符串, 待注入文件名, call三步

字节码 36 00 00 00

第一个字节为opcode, 第二个字节为寄存器编号, 第三个字节为常量池下表(从下往上数)

字节码为27 01 01 00

第一个字节为opcode, 第二个字节为寄存器编号, 第三个字节为常量池下表(从下往上数)

42 00 02 01

这里我有点没太明白, 按照官网表格的注释A+C-1=0, 参数为0个. 不过可以确定的是第二个字节为require的寄存器编号

首先跳过前置段, 找到main, 然后解析main proto的信息

将原本的信息解析完毕后, 需要插入常量和指令

最后更新字段数据

最终效果成功注入

模板信息

完整代码见https://github.com/stickycookie/luajitInject

参考资料:https://www.anquanke.com/post/id/87281

​ https://en.wikipedia.org/wiki/LEB128

​ https://www.mickaelwalter.fr/reverse-engineering-luajit/

 
--target.lua
function Test(x)
    print("Test " .. x)
end
 
Test("enter main==>test()")
require("addLib")
 
function fun1()
    print("Test in target.lua fun1 function...")
end
function fun2()
    print("Test in target.lua fun2 function...")
end
 
print("Test in target.lua main function...")
print(add(1,2))
--target.lua
function Test(x)
    print("Test " .. x)
end
 
Test("enter main==>test()")
require("addLib")
 
function fun1()
    print("Test in target.lua fun1 function...")
end
function fun2()
    print("Test in target.lua fun2 function...")
end
 
print("Test in target.lua main function...")
print(add(1,2))
 
 
 
 
int ReadUleb128(unsigned char*& buf)
{
    unsigned int result;
    unsigned char cur;
 
    result = *buf++;
    if (result > 0x7f)
    {
        cur = *buf++;
        result = (result & 0x7f) | (unsigned int)((cur & 0x7f) << 7);
        if (cur > 0x7f)
        {
            cur = *buf++;
            result |= (unsigned int)(cur & 0x7f) << 14;
            if (cur > 0x7f)
            {
                cur = *buf++;
                result |= (unsigned int)(cur & 0x7f) << 21;
                if (cur > 0x7f)
                {
                    cur = *buf++;
                    result |= (unsigned int)cur << 28;
                }
            }
        }
    }
    return result;
}
void WriteUleb128(unsigned char*& buf, int x)
{
    unsigned int denominator = 0x80;
    unsigned char flag = 0x80;
 
    for (int i = 0; i < 5; i++)
    {
        if (x < denominator)
        {
            buf[i] = (unsigned char)x;
            i++;
            buf += i;
            return;
        }
        buf[i] = (flag) | (unsigned char)(x % denominator);
        x = x >> 7;
    }
}
int ReadUleb128(unsigned char*& buf)
{
    unsigned int result;
    unsigned char cur;
 
    result = *buf++;
    if (result > 0x7f)
    {
        cur = *buf++;
        result = (result & 0x7f) | (unsigned int)((cur & 0x7f) << 7);
        if (cur > 0x7f)
        {
            cur = *buf++;
            result |= (unsigned int)(cur & 0x7f) << 14;
            if (cur > 0x7f)
            {
                cur = *buf++;
                result |= (unsigned int)(cur & 0x7f) << 21;
                if (cur > 0x7f)
                {
                    cur = *buf++;
                    result |= (unsigned int)cur << 28;
                }
            }
        }
    }
    return result;
}
void WriteUleb128(unsigned char*& buf, int x)
{
    unsigned int denominator = 0x80;
    unsigned char flag = 0x80;
 
    for (int i = 0; i < 5; i++)
    {
        if (x < denominator)
        {
            buf[i] = (unsigned char)x;
            i++;
            buf += i;
            return;
        }
        buf[i] = (flag) | (unsigned char)(x % denominator);
        x = x >> 7;
    }
}
\OP** \A** \B** \C/D** \Description**
GGET dst str A = _G[D]
 
 
\OP** \A** \D** \Description**
KSTR dst str Set A to string constant D
 
 
\OP** \A** \B** \C/D** \Description**
CALL base lit lit Call: A, ..., A+B-2 = A(A+1, ..., A+C-1)
 
 
struct ProtoHeader
{
    int protoSize, complexCnt, numericCnt, instructionCnt;
    unsigned char flags, argCnt, frameSize, upValueCnt;
};
struct Proto
{
    ProtoHeader ph;
    unsigned char* instructions, * constants;
    int instructionsSize, constantsSize;
};
 
void IngoreSeg(unsigned char*& buf, int n)
{
    while (n--)
    {
        int size = ReadUleb128(buf);
        buf += size;
    }
}
Proto* ReadProto(unsigned char* buf)
{
    unsigned char* ed = buf;
    int size = ReadUleb128(ed);
    ed += size;
 
    Proto* proto = new Proto;
    proto->ph.protoSize = ReadUleb128(buf);
    proto->ph.flags = ReadU8(buf);
    proto->ph.argCnt = ReadU8(buf);
    proto->ph.frameSize = ReadU8(buf);
    proto->ph.upValueCnt = ReadU8(buf);
    proto->ph.complexCnt = ReadUleb128(buf);
    proto->ph.numericCnt = ReadUleb128(buf);
    proto->ph.instructionCnt = ReadUleb128(buf);
 
    proto->instructionsSize = 4 * proto->ph.instructionCnt;//每条指令4个字节
    proto->instructions = new unsigned char[proto->instructionsSize];
    memcpy(proto->instructions, buf, proto->instructionsSize);
    buf += 4 * proto->ph.instructionCnt;
 
    proto->constantsSize = ed - buf;
    proto->constants = new unsigned char[proto->constantsSize];
    memcpy(proto->constants, buf, proto->constantsSize);
    buf += proto->constantsSize;
    return proto;
}
 
IngoreSeg(filePtr, targetSeg);
Proto* proto = ReadProto(filePtr);
struct ProtoHeader
{
    int protoSize, complexCnt, numericCnt, instructionCnt;
    unsigned char flags, argCnt, frameSize, upValueCnt;
};
struct Proto
{
    ProtoHeader ph;
    unsigned char* instructions, * constants;
    int instructionsSize, constantsSize;
};
 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-3-22 09:51 被juice4fun编辑 ,原因:
收藏
免费 6
支持
分享
最新回复 (7)
雪    币: 8887
活跃值: (4193)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
谢谢楼主这么好的东西
2022-3-22 09:22
0
雪    币: 3633
活跃值: (2708)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
大佬
2022-3-25 16:42
0
雪    币: 8437
活跃值: (5031)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
4
mark
2022-3-25 17:33
0
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
6666
2022-4-27 09:53
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
不错。可以研究luajit反编译了
2022-4-30 19:25
0
雪    币: 8764
活跃值: (5708)
能力值: ( LV13,RANK:296 )
在线值:
发帖
回帖
粉丝
7
mark
2022-4-30 20:25
0
雪    币: 631
活跃值: (3006)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
8
mark
2022-5-21 17:42
0
游客
登录 | 注册 方可回帖
返回
//