包含javaluac的词条
本篇文章给大家谈谈javaluac,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
chunk总体结构(头部)
二进制chunk主要分为两部分:
可以使用 xxd 命令观察一下 luac 文件
1.头部
头部共占用30个子节(因平台而异)
其中包含:
a.签名
很多二进制格式都会以固定的魔数开始(Magic Number)开始
(Java的class文件,魔数是四字节0xCAFEBABC)
Lua二进制chunk的魔数(也叫做签名,Signature)也是四个字节码,分别是 ESC、L、u、a 的ASCII码
十六进制表示是0x1B4C7561,字符串就是\x1bLua
其主要作用就是快速识别文件格式的作用
当Lua虚拟机试图加载一个chunk文件,发现其不是以这个开头的,就会拒绝加载文件
b.版本号
签名之后的一个字节,记录二进制chunk文件所对应的Lua版本号
有三个部分构成:
c.格式号
版本号之后的一个子节记录二进制chunk格式号
Lua加载二进制chunk时,也会检查格式号
如果和虚拟机本身的格式号不匹配,就拒绝加载该文件
Lua官方使用的格式号是 0
d.LUAC_DATA
格式号之后的六个字节在Lua官方实现里叫LUAC_DATA
其中前两个字是0x1993,这是Lua 1.0发布的年份
后四个子节依次是:回车符(0x0D)、换行符(0x0A)、替换符(0x1A)和另一个换行符
同样也是校验的作用,如果虚拟机加载二进制chunk时发现这六个字节不一样,就会认为文件损坏,拒绝加载
e.整数和Lua虚拟机指令宽度
接下来的几个数分别记录 cint、size_t、Lua虚拟机指令、Lua整数和Lua浮点数这五种数据类型,在而微软禁止chunk里占用的字节数。
同样也会检查这五种数据所占用的字节数,如果和期望数值不匹配则拒绝加载
f.LUAC_INT
解析来的n个子节存放 Lua 整数值 0x5678
是为了检验二进制 chunk 的大小端方式,Lua 会用虚拟机在加载二进制 chunk 时,会利用这个数据检查其大小端方式和本机是否匹配,如果不匹配就会拒绝记载
g.LUAC_NUM
头部的最后 n 个子节存放 Lua 浮点数 370.5
同样是为了检测二进制 chunk 所使用的浮点数格式,如果不匹配就拒绝加载
(主流平台和语言一般都采用 IEEE 754 浮点数格式)
怎么学好C语言,我对C语言没有基础的
我是一个程序员,参加工作的时间也不长。对于学习C,我有一些粗浅的看法如下:
1.掌握基本的理论知识。
刚开始学习编程时,掌握基础理论的知识是非常重要的。不然就会学的不系统,不完全。其实做程序员做到高级的,并不是编程有多厉害,而是他有足够的理论知识来解决别人的问题。现在一般较常见的两个学习途径:一是由C到C++或者VC方面,二是Java方面。这两个方面是目前最广泛的。 书用谭浩强的《C语言程序设计》,现在出到第三版了,有配套的习题解答。
2.多动手,勤动手。
当然,光掌握理论知识是远远不够的,要多动手编程。在这个过程中才能逐步消化、吸收所学的理论知识,强化自己的所学,并掌握一些基本的方法、技巧。这个过程也许枯燥,但这几乎是每个做程序员的人必须经历的过程。
3.掌握与编程相关的知识。
例如掌握一些计算机组成原理、逻辑设计、数据结构、算法等这些方面。这些方面学得好,十个里面有十个是高手。这也是由低阶像中、高阶方面发展的过程。
4.平时
平时多看些与编程有关的书籍,这样既可以开拓视野,又可以加深印象。上网时也可以看看CSDN,看看论坛里别人是怎么解决问题的。
O泡果奶等基于AndroLua应用破解
玩农药的时候,想着能有透视的辅助就好了,在网上找到了一个辅助应用,破解开发现是基于AndroLua的脚本应用。在逆向的同时,发现了现在火的很多应用,例如O泡果奶等,都使用了同样的加密方法。
AndroLua还是AndroLua_Pro应用的逆向,其实大同小异,框架不是逆向的重点,基本不会有人去改。主要是lua脚本的逆向,从luac到lua,可以直接用unluac.jar直接逆向。但是,加密程序会对脚本中的所有字符串进行加密混淆,比如字符串、函数名、类名。比如我遇到的这种,加密过程为,lua-luac-混淆加密-zlib压缩-base64编码。
zlib压缩的特征是inflate等相关方法的应用,base64编码的特征就是编码的解码表。这里主要关注的就是字符串加密混淆的方法,也是常见的异或加密,这种加密方法加密解密的过程是一样的。
找到了unluac.jar的源码,在进行字符串解码的时候,进行解密操作,就可以复原出真实的lua脚本。但是在实际使用的时候,对中文的复原不太友好,猜测可能与UTF-8编码有关,我在Python和Java上分别对用串汉字进行UTF-8编码产生的字节竟然不一样。
这个就比较容易了,根据inflate特征可以知道是zlib压缩,为求稳妥,找到对应版本的zlib直接调api就行,这里用的是Python下的zlib。
base64的特征还是很明显的,就是解码表,github上搜一下就能搜到需要的源码。
至此,基本上现在常见的lua脚本加密的逆向过程就完成了。
最后接一个贴士,
Linux lua中require "bit"
为了方便代码管理,通常会把lua代码分成不同的模块,然后在通过require函数把它们加载进来。现在看看lua的require的处理流程。
函数原型:require(modname) ---modname ----加载的模块名称
首先Lua提供高级的require函数来加载运行库。粗略的说require和dofile完成同样的功能但有两点不同:
1、require会搜索目录加载文件
2、require会判断是否文件已经加载避免重复加载同一文件。
由于上述特征,require在Lua中是加载库的更好的函数。
require函数实现了不同lua文件的加载,类似于C++中的include,java中的import。
require使用的路径和普通的路径还是有些区别,我们一般见到的路径都是一个目录列表。require的路径是一个模式列表,每一个模式指明一种由虚文件名(require的参数modname)转成实文件名的方法。更明确地说,每一个模式是一个包含可选的问号(?)的文件名。匹配的时候Lua会首先将问号用虚文件名替换,然后看是否有这样的文件存在。如果不存在继续用同样的方法用第二个模式匹配。例如,路径如下:
?; ?.lua; c:\windows\?; /usr/local/lua/?/?.lua调用require("add")时会试着打开以下这些文件:
add
add.lua
c:\windows\add
/usr/local/lua/add/add.lua
为了确定路径,Lua首先检查全局变量LUA_PATH是否为一个字符串,如果是则认为这个串就是路径;否则require检查环境变量LUA_PATH的值,如果两个都失败require使用固定的路径(典型的"?;?.lua").
require函数的实现原理如下:
--require 函数的实现
function require(name)
if not package.loaded[name] then
local loader = findloader(name) //这一步演示在代码中以抽象函数findloader来表示
if loader == nil then
error("unable to load module" .. name)
end
package.loaded[name] = true
local res = loader(name)
if res ~= nil then
package.loaded[name] = res
end
end
return package.loaded[name]
end
require(在lua中它是ll_require函数)函数会在路径中搜索输入的文件路径,大致流程如下:
1、package.loaded
一个用于控制哪些模块已经加载的表,该表由require使用。当require一个模块名为modname的模块且package.loaded[modname]不为false时,require仅返回package.loaded[modname]存储的值.
2、 package.preload
为特定模块存储加载器的一个表。查找modname, 如果preload存在,那么就把它作为loader,调用loader(L)
3、package.path
查找lua库modname,这个库是通过module函数定义的,对于顶层的lua库,文件名和库名是一 样的而且不需要调用显式地在lua文件中调用module函数(在ll_require函数中可以看到处理方式),也就是说lua会根据lua文件直接完 成一个loader的初始化过程。
4、package.cpath(实现lua调用C函数)
查找c库,这个库是符合lua的一些规范的(export具有一定特征的函数接口),lua先已动态的方式加载该c库(.so),然后在库中查找并调用相应名字的接口,例如:luaopen_hello_world
5、已第一个"."为分割,将模块名划分为:(main, sub)的形式,根据package.cpath查找main,如果存在,就加载该库并查询相应的接口:luaopen_main_sub,例如:先查找 hello库,并查询luaopen_hello_world接口
6、得到loder后,用modname作为唯一的参数调用该loader函数。当然参数是通过lua的栈传递的,所以loader的原型必须符合lua的规范:int LUA_FUNC(lua_State *L)
ll_require会将这个loader的返回值符给package.loaded[modelname],如果loader不返回值同时 package.loaded[modelname]不存在时, ll_require就会把package.loaded[modelname]设为true。最后ll_reuqire把package.loaded [modelname]返回给调用者。
require的另一个功能是避免重复加载同一个文件两次。Lua保留一张所有已经加载的文件的列表(使用table保存)。如果一个加载的文件在表中存在require简单的返回;表中保留加载的文件的虚名,而不是实文件名。所以如果你使用不同的虚文件名require同一个文件两次,将会加载两次该文件。比如require "foo"和require "foo.lua",路径为"?;?.lua"将会加载foo.lua两次。我们也可以通过全局变量_LOADED访问文件名列表,这样我们就可以判断文件是否被加载过;同样我们也可以使用一点小技巧让require加载一个文件两次。比如,require "foo"之后_LOADED["foo"]将不为nil,我们可以将其赋值为nil,require "foo.lua"将会再次加载该文件。
javaluac的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于、javaluac的信息别忘了在本站进行查找喔。