利用Lua进行二进制文件的位操作

1.纯lua的二进制位操作

lua的二进制文件主要利用string.byte()读取某个字节,string.char()写入,示例代码如下:

function v:xorFile(inputFile,outputFile)
    local fileIn,err = io.open(inputFile,"rb")
    local content = fileIn:read("*all")
    local length = fileIn:seek("end")
    fileIn:close()
    local fileOut,err = io.open(outputFile,"wb")
    fileOut:seek("set",0)
    local item
    for i=1,length do
        item = tonumber(string.byte(content,i))
        item = bit:_xor(item,186)
        fileOut:write(string.char(item))
    end
    fileOut:close()
end

这是对整个二进制文件进行异或操作,那么对某个32位的uint如何操作?比如把第posSrc位的uint32异或posDst位的uint32

function v:XORuint32(inputFile,outputFile,posSrc,posDst)
    local fileIn,err = io.open(inputFile,"rb")
    local content = fileIn:read("*all")
    local length = fileIn:seek("end")
    fileIn:seek("set",0)
    local dataA = fileIn:read(posSrc-1)
    fileIn:seek("set",posSrc+4)
    local dataB = fileIn:read("*all")
    fileIn:close()

    local value1 = tonumber(string.byte(content,posSrc+1))
    local value2 = tonumber(string.byte(content,posSrc+2))
    local value3 = tonumber(string.byte(content,posSrc+3))
    local value4 = tonumber(string.byte(content,posSrc+4))

    local key1 = tonumber(string.byte(content,posDst+1))
    local key2 = tonumber(string.byte(content,posDst+2))
    local key3 = tonumber(string.byte(content,posDst+3))
    local key4 = tonumber(string.byte(content,posDst+4))

    value1 = bit:_xor(value1,key1)
    value2 = bit:_xor(value2,key2)
    value3 = bit:_xor(value3,key3)
    value1 = bit:_xor(value4,key4)

    local fileOut,err = io.open(outputFile,"wb")
    fileOut:seek("set",0)
    fileOut:write(dataA)
    fileOut:write(string.char(value1))
    fileOut:write(string.char(value2))
    fileOut:write(string.char(value3))
    fileOut:write(string.char(value4))
    fileOut:write(dataB)
    fileOut:close()
end

附上bit的代码

bit={data32={}}
for i=1,32 do
    bit.data32[i]=2^(32-i)
end

function bit:d2b(arg)
    local   tr={}
    for i=1,32 do
        if arg >= self.data32[i] then
            tr[i]=1
            arg=arg-self.data32[i]
        else
            tr[i]=0
        end
    end
    return   tr
end   --bit:d2b

function    bit:b2d(arg)
    local   nr=0
    for i=1,32 do
        if arg[i] ==1 then
            nr=nr+2^(32-i)
        end
    end
    return  nr
end   --bit:b2d

function    bit:_xor(a,b)
    local   op1=self:d2b(a)
    local   op2=self:d2b(b)
    local   r={}

    for i=1,32 do
        if op1[i]==op2[i] then
            r[i]=0
        else
            r[i]=1
        end
    end
    return  self:b2d(r)
end --bit:xor

function    bit:_and(a,b)
    local   op1=self:d2b(a)
    local   op2=self:d2b(b)
    local   r={}

    for i=1,32 do
        if op1[i]==1 and op2[i]==1  then
            r[i]=1
        else
            r[i]=0
        end
    end
    return  self:b2d(r)

end --bit:_and

function    bit:_or(a,b)
    local   op1=self:d2b(a)
    local   op2=self:d2b(b)
    local   r={}

    for i=1,32 do
        if  op1[i]==1 or   op2[i]==1   then
            r[i]=1
        else
            r[i]=0
        end
    end
    return  self:b2d(r)
end --bit:_or

function    bit:_not(a)
    local   op1=self:d2b(a)
    local   r={}

    for i=1,32 do
        if  op1[i]==1   then
            r[i]=0
        else
            r[i]=1
        end
    end
    return  self:b2d(r)
end --bit:_not

function    bit:_rshift(a,n)
    local   op1=self:d2b(a)
    local   r=self:d2b(0)

    if n < 32 and n > 0 then
        for i=1,n do
            for i=31,1,-1 do
                op1[i+1]=op1[i]
            end
            op1[1]=0
        end
        r=op1
    end
    return  self:b2d(r)
end --bit:_rshift

function    bit:_lshift(a,n)
    local   op1=self:d2b(a)
    local   r=self:d2b(0)

    if n < 32 and n > 0 then
        for i=1,n   do
            for i=1,31 do
                op1[i]=op1[i+1]
            end
            op1[32]=0
        end
        r=op1
    end
    return  self:b2d(r)
end --bit:_lshift


function    bit:print(ta)
    local   sr=""
    for i=1,32 do
        sr=sr..ta[i]
    end
    print(sr)
end

以上代码异或整个文件,1M的文件需要15秒左右,显然太慢,于是换个脚本,用python试试

2.python的二进制位操作

import binascii
import struct
import sys


def str2hex(str):
    hexs = []
    for s in str:
        tmp = (hex(ord(s)).replace('0x',''))
        if len(tmp) == 2:
            hexs.append(tmp)
        else:
            hexs.append('0'+tmp)
        return hexs

arr= ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
arr2 = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]

def tran(r):
    for i in range(len(arr)):
        if r == arr[i]:
            return arr2[i]

def packRes(input,output,key):
    f = open(input,'rb+')

    hexs = []
    while True:
        t = f.read(1)
        if len(t) == 0:
            break
        hexs.extend(str2hex(t))

    f.close()

    ff = open(output,'wb')
    for i in  range(len(hexs)):
        a = tran(hexs[i][0])*16+tran(hexs[i][1])
        B = struct.pack('B',a^key)
        ff.write(B)
    ff.close()


def main(p1,p2,p3):
    print(p1)
    print(p2)
    print(p3)
    try:
        packRes(p1,p2,int(p3))
        sys.exit(0)
    except:
        sys.exit(1)
    finally:
        pass

if __name__ == "__main__":
    if len(sys.argv) >= 1:
        p1 = sys.argv[1]
        p2 = sys.argv[2]
        p3 = sys.argv[3]
        main(p1,p2,p3)

同样的文件要1秒左右,效率提升显著,然而还是不满足需求,还是试试C++吧

3.c++的二进制位操作

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdlib> 

int main(int argc, char* argv[])
{
	int i, count, len;
	int key;
	char buff[1024];
	static char tmpfile[] = "~u~0_sw~.f~l";
	FILE * in, *out;

	if (argc <3)
	{
		printf("Less Parameter !\n");
		printf("Parameter number must at least 2 !!\n");
		return 1;
	}

	len = strlen(argv[2]);
	in = fopen(argv[1], "rb");
	out = fopen(tmpfile, "wb"); /* creat a temp file */
	key = std::atoi(argv[3]);
	
	if (in == NULL)
	{
		printf("Input File \'%s\' not found !!\n", argv[1]);
		exit(1);
	}
	if (out == NULL)
	{
		printf("Can not creat temp file \'%s\'\n", tmpfile);
		exit(2);
	}

	while (!feof(in))
	{
		count = fread(buff, 1, 1024, in);
		for (i = 0;i <count;i++)
			buff[i] ^= 119;
			//buff[i] ^= argv[2][i%len];
		fwrite(buff, 1, count, out);
	}

	fclose(in);
	fclose(out);
	//printf(argv[1]);
	//printf(argv[2]);
	if( strcmp(argv[1], argv[2]) == 0)
	{
		remove(argv[1]);
		printf("the key is: %d", key);
	}
	
	rename(tmpfile, argv[2]);
	return 0;
}

1M左右,大概需要0.0006秒左右。因为我们最终是在lua脚本里用,所以接下来说下lua如何调用python

4.lua调用python和C

lua里面用os.excute来调用本地脚本。

首先看下调用python,由于python是跨平台的,MAC和WIN10下代码一致:

os.excute("python xxx.py inputFIle outputFile key")

在win10下调用控制台程序的话:VS新建控制台应用程序,调试成功后cd到exe 目录

os.excute("xxx.exe inputFIle outputFile key")

在mac下先cd到cpp目录用g++编译

g++ xxx.cpp

生成a.out

os.excute("./a.out inputFIle outputFile key")

5.小结

有人会喜欢那语言做比较,我认为语言是看场合的,就像你比较匕首和导弹,没有太大的意义。主要看武器在谁的手里,怎么去使用它。

上面对比来看,貌似python比lua效率高很多,然而,我们本不该在lua里面执行大体积二进制文件的位操作,Lua作为C的触手,应该在C里面绑定一个方法让lua调用,这样lua的效率就是C的效率(当然,要扣除一点调用C的成本)。

lua和python在不同场合有着各自的生命力。

猜你喜欢

转载自blog.csdn.net/woshixuhua/article/details/81634648