前言
环境准备
Vscode编辑器
Lua 在线运行环境
菜鸟教程 Lua语言
Lua 官方下载地址
基于学习效率的考量,太基础的东西,就翻翻菜鸟教程吧。
变量
全局变量
Lua语言中变量默认是全局变量,并且其初始化的值就是nil,所以访问一个没有初始化的全局变量也不会出错。
如果想删除一个全局变量,也很简单,给它赋值为nil就行了。
G表
_G表与_Env表
Lua把所有全局变量都存在一个常规的table中(即全局环境),然后把这个table保存在一个全局变量_G中
然后在脚本中就可以用pairs去打印_G的所有变量。
打印_G的所有变量
a=123;
b=1234;
c="114514"
for n in pairs(_G)
do
print(n) --打印出_G表中的所有变量
end
打印全局变量的值
a='114514';
print(a);
print(_G["a"]);
print(_G.a);
局部变量
local a=xxx;
数据类型
string
数字字符串计算时会转成数字
print("2"+6);
print("114".."514"+1919810); -- .. 是字符串拼接!
字符串块
[[]]表示一块字符串
html = [[
<html>
<head></head>
<body>
<a href="http://www.runoob.com/">菜鸟教程</a>
</body>
</html>
]]
print(html)
字符串长度
a="114514"
print(#a)
print(#"114514")
--[[ output:
6
6
]]
table
Lua中,表就是一个关联数组,索引值可以是数字也可以是字符串
a={}
a['114514']=114514
a[2]=2
b=3
a[b]=3
for i,j in pairs(a) do
print(i .. " : " .. j)
end
在Lua中,ipairs和pairs都用于遍历table,但是它们有一些重要的区别:
• pairs可以用于遍历任何类型的table,无论其键是整数还是非整数,有序还是无序。它并不保证遍历的顺序,每次运行可能会得到不同的顺序。
• ipairs只能用于遍历具有连续正整数键的table(即数组部分的table)。它按照键的升序遍历表中的元素,从1开始,直到遇到第一个nil值。
a={'web','rev','pwn','crypto','Misc','blockchain'}
for i,j in pairs(a) do -- ipairs是遇到键值为nil就退出
print(i.." "..j)
end
--[[
1 web
2 rev
3 pwn
4 crypto
5 Misc
6 blockchain
]]
a={'web','rev','pwn','crypto','Misc','blockchain'}
for i=1,7 do
print(a[i])
end
--[[
web
rev
pwn
crypto
Misc
blockchain
nil //访问未初始化的值都是 nil
]]
在lua中初始化表,如果只有键值,没有键,那么会自动给它分配一个键为1,第二个分配一个键为2 …
a = {[1] = "a1", [2] = "a2", [3] = "a3", [4] = "a4"}
for key, value in ipairs(a) do
print(key, value)
end
print()
b = {[1] = "b1", [2] = "b2", [3] = "b3", [4] = "b4","b5","b6"}
for key, value in ipairs(b) do
print(key, value)
end
--[[
1 a1
2 a2
3 a3
4 a4
1 b5 -- 原来键为1,2 的键值被b1 b2 覆盖了
2 b6
3 b3
4 b4
]]
然后对于没有键的表,可以进行sort
a = {114, 112, 111, 514}
table.sort(a, function(v1, v2) return v1 < v2 end) -- 对值进行排序 ,好熟悉,这不就C语言里面自定义排序吗。
for key, value in ipairs(a) do -- 使用 ipairs 而不是 pairs
print(key, value)
end
--[[
1 111
2 112
3 114
4 514
]]
循环
for 循环
for i=var1,var2,var3 do -- 从var1 变化到 var2 step=var3
-- <执行体>
end
泛型for循环
a = {"c", "python", "js","lua"}
for i, v in ipairs(a) do
print(i, v)
end
while 循环
while(condition)
do
statements
end
repeat-until
这不就是do while 吗…
a = 10
--[ 执行循环 --]
repeat
print("a的值为:", a)
a = a + 1
until( a > 15 )
goto label
注意lable的命名
::name::
a=1
::add:: a=a+1
if a<3 then
goto add
end
函数
C系列的函数的返回值不能是多个,Lua却可以有多个函数返回值
optional_function_scope function function_name( arg1, arg2,...) -- option_function_scope 可以指定返回值是全局还是局部变量
function_body
return result
end
运算符
算数运算符
逻辑运算符
与python一样
• and
• or
• not
关系运算符
其他都和C/C++类似,除了一个符号
~= 为不等于
特殊运算符
.. --代表字符串拼接,前面的代码中有用到
# --用于返回字符串的长度
运算符的优先级
从高到低
- ^
- not - (unary)
- * / %
- + -
- … (两个点,这
傻逼编辑器,输入两个点,显示三个点) - < > <= >= ~= ==
- and
- or
字符串的操作
前面已经写到了字符串,现在就写一些一些经常用到的字符串方法
string.upper(argument) 字符串全部转为大写字母。
string.lower(argument) 字符串全部转为小写字母。
string.reverse(arg) 字符串反转
string.len(arg) == #arg
数组
迭代器
GoogleCTF 2023 zermatt
这题就是一道lua的混淆题
v8,v9~v22就是通过一个局部变量去存储_G表中对应键的函数,v7其实就是一个Deobfuscation函数,后面跟着的是混淆的字符串
把代码抠下来,然后跑一下
local v0 = string.char;
local v1 = string.byte;
local v2 = string.sub;
local v3 = bit32 or bit;
local v4 = v3.bxor;
local v5 = table.concat;
local v6 = table.insert;
local function v7(v24, v25)
local v26 = 0;
local v27;
while true do
if (v26 == 1) then return v5(v27); end
if (v26 == 0) then
v27 = {};
for v44 = 1, #v24 do
v6(v27, v0(v4(v1(v2(v24, v44, v44 + 1)), v1(
v2(v25, 1 + ((v44 - 1) % #v25),
1 + ((v44 - 1) % #v25) + 1))) % 256));
end
v26 = 1;
end
end
end
print(v7("\79\15\131\30\40\13\20\203",
"\59\96\237\107\69\111\113\185"));
-- tonumber
然后把这些都转一下
local v8 = _G["tonumber"];
local v9 = _G["string"]["byte"];
local v10 =_G["string"]["char"];
local v11 = _G["string"]["sub"];
local v12 = _G["string"]["gsub"];
local v13 = _G["string"]["rep"];
local v14 = _G["table"]["concat"];
local v15 = _G["table"]["insert"];
local v16 = _G["math"]["ldexp"];
local v17 = _G["getfenv"] or
function() return _ENV; end;
local v18 = _G["setmetatable"];
local v19 = _G["pcall"];
local v20 = _G["select"];
local v21 =
_G["unpack"] or
_G["table"]["unpack"];
local v22 = _G["tonumber"];
这样子看着舒服一点。
然后跑一下代码,
如果输入错误,就会返回LOSE
如果我们在输入的时候,通过CTRL+C去中断,那么会报错,然后程序还打印了堆栈
在VSCODE中直接CTRL+G 2386是error函数不用管,我们直接跳转到第2237行去查看
v293是索引值,v191是表,我们可以打印一下v191的内容。但是注意,直接print(v191)只是打印地址。
想要打印出表中的每个键值,可以看看这篇stack Overlow的文章 Link from Stack Overlow
COPY FROM STACK OVERLOW
↓
function print_table(node)
local cache, stack, output = {},{},{}
local depth = 1
local output_str = "{\n"
while true do
local size = 0
for k,v in pairs(node) do
size = size + 1
end
local cur_index = 1
for k,v in pairs(node) do
if (cache[node] == nil) or (cur_index >= cache[node]) then
if (string.find(output_str,"}",output_str:len())) then
output_str = output_str .. ",\n"
elseif not (string.find(output_str,"\n",output_str:len())) then
output_str = output_str .. "\n"
end
-- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
table.insert(output,output_str)
output_str = ""
local key
if (type(k) == "number" or type(k) == "boolean") then
key = "["..tostring(k).."]"
else
key = "['"..tostring(k).."']"
end
if (type(v) == "number" or type(v) == "boolean") then
output_str = output_str .. string.rep('\t',depth) .. key .. " = "..tostring(v)
elseif (type(v) == "table") then
output_str = output_str .. string.rep('\t',depth) .. key .. " = {\n"
table.insert(stack,node)
table.insert(stack,v)
cache[node] = cur_index+1
break
else
output_str = output_str .. string.rep('\t',depth) .. key .. " = '"..tostring(v).."'"
end
if (cur_index == size) then
output_str = output_str .. "\n" .. string.rep('\t',depth-1) .. "}"
else
output_str = output_str .. ","
end
else
-- close the table
if (cur_index == size) then
output_str = output_str .. "\n" .. string.rep('\t',depth-1) .. "}"
end
end
cur_index = cur_index + 1
end
if (size == 0) then
output_str = output_str .. "\n" .. string.rep('\t',depth-1) .. "}"
end
if (#stack > 0) then
node = stack[#stack]
stack[#stack] = nil
depth = cache[node] == nil and depth + 1 or depth - 1
else
break
end
end
-- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
table.insert(output,output_str)
output_str = table.concat(output)
print(output_str)
end
然后在v191的上下都print一下。
然后重新运行一下。
这里的v9其实就是我们后面输入的提示
我们随便输入一些东西
然后居然直接把Flag打印出来了。
评论区