侧边栏壁纸
  • 累计撰写 38 篇文章
  • 累计创建 23 个标签
  • 累计收到 9 条评论

目 录CONTENT

文章目录

【PL-Learn】Lua语言入门

Fup1p1
2023-07-06 / 0 评论 / 0 点赞 / 621 阅读 / 6,441 字 / 正在检测是否收录...

前言

环境准备

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;

数据类型

image-1688624845208

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

运算符

算数运算符

image-1688645925514

逻辑运算符

与python一样
and
or
not

关系运算符

其他都和C/C++类似,除了一个符号

~= 为不等于

特殊运算符

..  --代表字符串拼接,前面的代码中有用到
#   --用于返回字符串的长度

运算符的优先级

从高到低

  1. ^
  2. not - (unary)
  3. * / %
  4. + -
  5. … (两个点,这傻逼编辑器,输入两个点,显示三个点)
  6. < > <= >= ~= ==
  7. and
  8. or

字符串的操作

前面已经写到了字符串,现在就写一些一些经常用到的字符串方法
string.upper(argument) 字符串全部转为大写字母。
string.lower(argument) 字符串全部转为小写字母。
string.reverse(arg) 字符串反转
string.len(arg) == #arg

数组

迭代器

GoogleCTF 2023 zermatt

这题就是一道lua的混淆题
image-1688705710463

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"];

这样子看着舒服一点。
然后跑一下代码,
image-1688707457079
如果输入错误,就会返回LOSE
如果我们在输入的时候,通过CTRL+C去中断,那么会报错,然后程序还打印了堆栈
image-1688707586649
在VSCODE中直接CTRL+G 2386是error函数不用管,我们直接跳转到第2237行去查看
image-1688707909838
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一下。
image-1688708325427
然后重新运行一下。
image-1688708311155
这里的v9其实就是我们后面输入的提示
我们随便输入一些东西
然后居然直接把Flag打印出来了。
image-1688708241598

0

评论区