看雪CTF第十五题
1、直接运行起来,再用OD附加
在此处luajit加载并调用main函数
004021C7 E8 64FE0000 call CrackMe. ; luaL_newstate
004021CC 8BF0 mov esi,eax
004021CE push esi
004021CF E8 9C000100 call CrackMe. ; luaL_openlibs(lua_State *L)
004021D4 push ebx
004021D5 push 0x275
004021DA 8D4424 3C lea eax,dword ptr ss:[esp+0x3C]
004021DE push eax
004021DF push esi
004021E0 E8 5B040100 call CrackMe. ; int luaL_loadbuffer(lua_State*L,const char*buff,size_t size,const char*name
004021E5 push ebx
004021E6 push esi
004021E7 E8 C41B0100 call CrackMe.00413DB0
004021EC 883E4800 push CrackMe.00483E88 ; ASCII "main"
004021F1 EED8FFFF push -0x2712
004021F6 push esi
004021F7 E8 call CrackMe. ; void (lua_getfield) (lua_State *L, int idx, const char *k);
004021FC push edi
004021FD push esi
004021FE E8 DD0E0100 call CrackMe.004130E0 ; lua_pushstring
6A push 0x1
push esi
E8 A51B0100 call CrackMe.00413DB0 ; lua_call
2、在luaL_loadbuffer出下断开dump下luajit的bytecode
使用luajit-decomp进行反编译,注意:可以此处是LuaJIT-2.1.0-beta3,需编译替换luajit-decomp中对应的文件
在IDA中字符串列表中搜索lua可以知道lua和luajit的版本。注意:由于有反调试,先运行程序在用OD附加然后dump
Address Length Type String
------- ------ ---- ------
.text:00471CFC 0000002E C PANIC: unprotected error in call to Lua API (
.text:00473EA0 C 'module' not called from a Lua function
.text:00473F40 C .\\?.lua;!\\lua\\?.lua;!\\lua\\?\\init.lua;
.text: C Lua function expected
.text: C LuaJIT 2.1.-beta3
.text:00473D1C 0000000D C luaJIT_BC_%s
.text: 0000000C C lua_debug>
.text:00473D2C 0000000B C luaopen_%s
.text:00473F34 0000000A C LUA_CPATH
.text:00473F74 0000000A C LUA_NOENV
.text:00473F68 C LUA_PATH
.text: C Lua 5.1
dump下luajit的bytecode:
-- BYTECODE -- lua.bytes:-
function someFunc0()
var_0_4 = INPUT_VAR_0_
var_0_5 = INPUT_VAR_1_
var_0_6 = INPUT_VAR_1_
var_0_3 = string.sub(var_0_4, var_0_5, var_0_6) --var_0_3 REPLACE-REPLACE
string.byte(var_0_3)
end -- BYTECODE -- lua.bytes:-
function someFunc1()
var_1_2 = INPUT_VAR_0_
var_1_1 = string.len(var_1_2)
if var_1_1 ~= then
--jump to (if previous if statement is false) -- JMP-JMP
var_1_1 = --var_1_1 NUMBER-NUMBER
return var_1_1
--location -- LOCATION-LOCATION
var_1_3 = INPUT_VAR_0_
var_1_4 = --var_1_4 NUMBER-NUMBER
var_1_2 = by(var_1_3, var_1_4)
var_1_3 = --var_1_3 NUMBER-NUMBER
var_1_1 = bit.bxor(var_1_2, var_1_3)
var_1_4 = INPUT_VAR_0_
var_1_5 = --var_1_5 NUMBER-NUMBER
var_1_3 = by(var_1_4, var_1_5)
var_1_4 = --var_1_4 NUMBER-NUMBER
var_1_2 = bit.bxor(var_1_3, var_1_4)
var_1_5 = INPUT_VAR_0_
var_1_6 = --var_1_6 NUMBER-NUMBER
var_1_4 = by(var_1_5, var_1_6)
var_1_5 = --var_1_5 NUMBER-NUMBER
var_1_3 = bit.bxor(var_1_4, var_1_5)
var_1_6 = INPUT_VAR_0_
var_1_7 = --var_1_7 NUMBER-NUMBER
var_1_5 = by(var_1_6, var_1_7)
var_1_6 = --var_1_6 NUMBER-NUMBER
var_1_4 = bit.bxor(var_1_5, var_1_6)
var_1_7 = INPUT_VAR_0_
var_1_8 = --var_1_8 NUMBER-NUMBER
var_1_6 = by(var_1_7, var_1_8)
var_1_7 = --var_1_7 NUMBER-NUMBER
var_1_5 = bit.bxor(var_1_6, var_1_7)
var_1_8 = INPUT_VAR_0_
var_1_9 = --var_1_9 NUMBER-NUMBER
var_1_7 = by(var_1_8, var_1_9)
var_1_8 = --var_1_8 NUMBER-NUMBER
var_1_6 = bit.bxor(var_1_7, var_1_8)
var_1_9 = INPUT_VAR_0_
var_1_10 = --var_1_10 NUMBER-NUMBER
var_1_8 = by(var_1_9, var_1_10)
var_1_9 = --var_1_9 NUMBER-NUMBER
var_1_7 = bit.bxor(var_1_8, var_1_9)
var_1_10 = INPUT_VAR_0_
var_1_11 = --var_1_11 NUMBER-NUMBER
var_1_9 = by(var_1_10, var_1_11)
var_1_10 = --var_1_10 NUMBER-NUMBER
var_1_8 = bit.bxor(var_1_9, var_1_10)
var_1_11 = INPUT_VAR_0_
var_1_12 = --var_1_12 NUMBER-NUMBER
var_1_10 = by(var_1_11, var_1_12)
var_1_11 = --var_1_11 NUMBER-NUMBER
var_1_9 = bit.bxor(var_1_10, var_1_11)
var_1_12 = INPUT_VAR_0_
var_1_13 = --var_1_13 NUMBER-NUMBER
var_1_11 = by(var_1_12, var_1_13)
var_1_12 = --var_1_12 NUMBER-NUMBER
var_1_10 = bit.bxor(var_1_11, var_1_12)
var_1_13 = INPUT_VAR_0_
var_1_14 = --var_1_14 NUMBER-NUMBER
var_1_12 = by(var_1_13, var_1_14)
var_1_13 = --var_1_13 NUMBER-NUMBER
var_1_11 = bit.bxor(var_1_12, var_1_13)
var_1_14 = INPUT_VAR_0_
var_1_15 = --var_1_15 NUMBER-NUMBER
var_1_13 = by(var_1_14, var_1_15)
var_1_14 = --var_1_14 NUMBER-NUMBER
var_1_12 = bit.bxor(var_1_13, var_1_14)
var_1_13 = var_1_1
var_1_14 = var_1_2
var_1_15 = var_1_3
var_1_16 = var_1_4
var_1_17 = var_1_5
var_1_18 = var_1_6
var_1_19 = var_1_7
var_1_20 = var_1_8
var_1_21 = var_1_9
var_1_22 = var_1_10
var_1_23 = var_1_11
var_1_24 = var_1_12
return var_1_13, var_1_14, var_1_15, var_1_16, var_1_17, var_1_18, var_1_19, var_1_20, var_1_21, var_1_22, var_1_23, var_1_24
end -- BYTECODE -- lua.bytes:-
function someFunc2()
var_2_1 = "bit" --var_2_1 STRING-STRING
require(var_2_1)
local randomFunction0 = function() end -- starts at lua.bytes:
by = randomFunction0
local randomFunction1 = function() end -- starts at lua.bytes:
main = randomFunction1
return
end
可以看出
someFunc0函数截取字符串指定位置的字符 并转换成byte
someFunc1函数对字符串调用someFunc0函数每个字符截取 并 xor
someFunc2中可以看出 by = randomFunction0 应该就是 by = someFunc0, main = randomFunction1 应该就是 main = someFunc1
3、调用完lua中的main函数后,从lua栈中依次取出每个字符加密后的byte, 然后再次进行 xor
0040222C push ebp
0040222D 6A F4 push -0xC
0040222F push esi
E8 AB0A0100 call CrackMe.00412CE0 ; lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum);
8BF8 mov edi,eax
6A F5 push -0xB
push esi
0040223A 83F7 xor edi,0x5
0040223D E8 9E0A0100 call CrackMe.00412CE0
8BD8 mov ebx,eax
6A F6 push -0xA
push esi
83F3 xor ebx,0x12
0040224A E8 910A0100 call CrackMe.00412CE0
0040224F 8BE8 mov ebp,eax
6A F7 push -0x9
push esi
83F5 0A xor ebp,0xA
E8 840A0100 call CrackMe.00412CE0
0040225C 83F0 xor eax,0x29
0040225F 6A F8 push -0x8
push esi
mov dword ptr ss:[esp+0x58],eax
E8 750A0100 call CrackMe.00412CE0
0040226B 83F0 xor eax,0x42
0040226E 6A F9 push -0x7
push esi
mov dword ptr ss:[esp+0x48],eax
E8 660A0100 call CrackMe.00412CE0
0040227A 83F0 xor eax,0x41
0040227D 6A FA push -0x6
0040227F push esi
mov dword ptr ss:[esp+0x60],eax
E8 570A0100 call CrackMe.00412CE0
83F0 xor eax,0x75
0040228C 6A FB push -0x5
0040228E push esi
0040228F mov dword ptr ss:[esp+0x60],eax
E8 480A0100 call CrackMe.00412CE0
83C4 add esp,0x40
0040229B 83F0 xor eax,0x61
0040229E 6A FC push -0x4
004022A0 push esi
004022A1 mov dword ptr ss:[esp+0x18],eax
004022A5 E8 360A0100 call CrackMe.00412CE0
004022AA 83F0 xor eax,0x35
004022AD 6A FD push -0x3
004022AF push esi
004022B0 mov dword ptr ss:[esp+0x24],eax
004022B4 E8 270A0100 call CrackMe.00412CE0
004022B9 xor eax,0x83
004022BE 6A FE push -0x2
004022C0 push esi
004022C1 mov dword ptr ss:[esp+0x34],eax
004022C5 E8 160A0100 call CrackMe.00412CE0
004022CA 83F0 xor eax,0x55
004022CD 6A FF push -0x1
004022CF push esi
004022D0 mov dword ptr ss:[esp+0x44],eax
004022D4 E8 070A0100 call CrackMe.00412CE0
004022D9 xor eax,0x94
004022DE 6A F3 push -0xD
004022E0 push esi
004022E1 mov dword ptr ss:[esp+0x54],eax
004022E5 E8 call CrackMe.
004022EA push esi
004022EB E8 call CrackMe. ; lua_close
4、最后每个byte和固定的值进行比较
004022F3 83FF cmp edi,0x18
004022F6 jnz short CrackMe.0040234C
004022F8 83FB cmp ebx,0x16
004022FB 4F jnz short CrackMe.0040234C
004022FD 83FD 1E cmp ebp,0x1E
4A jnz short CrackMe.0040234C
837C24 2F cmp dword ptr ss:[esp+0x30],0x2F
jnz short CrackMe.0040234C
837C24 cmp dword ptr ss:[esp+0x18],0x48
0040230E 3C jnz short CrackMe.0040234C
837C24 cmp dword ptr ss:[esp+0x28],0x11
jnz short CrackMe.0040234C
837C24 cmp dword ptr ss:[esp+0x20],0x21
0040231C 2E jnz short CrackMe.0040234C
0040231E 837C24 cmp dword ptr ss:[esp+0x10],0x37
jnz short CrackMe.0040234C
837C24 cmp dword ptr ss:[esp+0x14],0x33
0040232A jnz short CrackMe.0040234C
0040232C 817C24 1C >cmp dword ptr ss:[esp+0x1C],0x86
jnz short CrackMe.0040234C
837C24 cmp dword ptr ss:[esp+0x24],0x52
0040233B 0F jnz short CrackMe.0040234C
0040233D 817C24 2C >cmp dword ptr ss:[esp+0x2C],0x94
jnz short CrackMe.0040234C
5、可以提取3处xor的值
lua中main函数对每个字符xor的值
[112,101,100,105,121,49,50,51,52,53,54,55]
0040222C 处对lua输出的每个值进行异或
[0x5,0x12,0xa,0x29,0x42,0x41,0x75,0x61,0x35,0x83,0x55,0x94]
004022F3 处对上面两次异或后的结果和下面的值进行比较
[0x18,0x16,0x1e,0x2f,0x48,0x11,0x21,0x37,0x33,0x86,0x52,0x94]
6、用python进行解码
result = [0x18,0x16,0x1E,0x2F,0x48,0x11,0x21,0x37,0x33,0x86,0x52,0x94]
luaxor = [,,,,,,,,,,,]
codexor = [0x5,0x12,0xa,0x29,0x42,0x41,0x75,0x61,0x35,0x83,0x55,0x94] code = ''
for i in range(len(result)):
code += chr(result[i]^luaxor[i]^codexor[i]) print code
结果:maposafe2017
看雪CTF第十五题的更多相关文章
- 看雪CTF第十四题
from z3 import * dest=[] s = Solver() data = [, , , , , , , , , , , , , , , , , , , , , , , , , , , ...
- 看雪CTF第十题
__int64 sub_140006F50() { __int64 v0; // r8@1 __int64 v1; // r9@1 signed __int64 len; // rax@1 __int ...
- 2019看雪CTF 晋级赛Q2第四题wp
上次参加2019看雪CTF 晋级赛Q2卡在了这道题上,虽然逆出算法,但是方程不会解,哈哈哈哈,果然数学知识很重要呀,现在记录一下. 首先根据关键信息,根据错误提示字符串定位到这里: 1 int __t ...
- 看雪CTF第八题
IDA查看Exports有3个TlsCallback 只有TlsCallback_2有用 其中创建6个线程用于代码动态解码smc 只有前三个线程有用 分别对check_part1,check_part ...
- LeetCode第十五题-找出数组中三数和为0的答案
3Sum 问题简介: 给定n个整数的数组nums,是否有元素a,b,c在nums中,使a + b + c = 0? 找到数组中所有唯一的三元组,它们的总和为零 注:解决方案集不得包含重复的三元组 例如 ...
- leecode第十五题(三数之和)
class Solution { public: void quick_order(vector<int>& num, int star, int en)//快排 { int st ...
- 【leetcode 简单】 第三十五题 环形链表
给定一个链表,判断链表中是否有环. 进阶: 你能否不使用额外空间解决此题? /** * Definition for singly-linked list. * struct ListNode { * ...
- 输出1到最大的N位数 【微软面试100题 第六十五题】
题目要求: 输入数字n,按顺序输出从1到最大的n位10进制数. 例如,输入3,则输出1.2.3....999(最大的3位数). 参考资料:剑指offer第12题. 题目分析: 如果我们在数字前面补0的 ...
- C++异常安全的赋值运算符重载 【微软面试100题 第五十五题】
题目要求: 类CMyString的声明如下: class CMyString { public: CMyString(char *pData=NULL); CMyString(const CMyStr ...
随机推荐
- MySQL 5.7基于GTID复制的常见问题和修复步骤(二)
[问题二] 有一个集群(MySQL5.7.23)切换后复制slave报1236,其实是不小心在slave上执行了事务导致 Got fatal error 1236 from master when r ...
- 用python批量生成简单的xml文档
最近生成训练数据时,给一批无效的背景图片生成对应的xml文档,我用python写了一个简单的批量生成xml文档的demo,遇见了意外的小问题,记录一下. 报错问题为:ImportError: No m ...
- 潭州课堂25班:Ph201805201 WEB 之 CSS 第二课 (课堂笔记)
CSS 的引入方法: 第一种 : <!--直接在标签仙设置--><p style="color: yellow">CSS的第一种引入方法</p> ...
- bzoj 2013 上升计数
题意: 给一个数集和一个数d,问满足下列要求的排列数(相同的数要区分): a[i]+d>=a[i+1] ( i in [1,n) ) 因为数的给出顺序不重要,所以先排序,假如我们已经解决了前i ...
- jd-gui的使用方法
java的反编译工具,简单使用: 打开文件.单击“file”从中选择“Open File ...“选项,弹出一个文件选择框,可以选择要打开的文件,或者直接单击文件夹图标,直接弹出文件选择框:从文件选择 ...
- Qt.常用代码整理
窗口全屏化(此方法只对顶级窗口有效,对子窗口无效) window.showFullScreen() 字符串处理 Qt还提供了一种方便的字符串组合方式,使用QString::arg()函数,此函数的重载 ...
- ext2文件系统学习(二)—— 目录磁盘结构
创建镜像.mount等操作和上一篇一样,测试目录结构如下: 一些文件系统信息如下: Block size: 1024 Inodes per group: 128 Inode ...
- 使用uploadify上传图片时返回“Cannot read property 'queueData' of undefined”
在使用uploadify插件上传图片时,遇到一个比较坑的错误:上传时提示“Cannot read property 'queueData' of undefined”. 遇到这个问题有点无语,因为这个 ...
- 使用AngularJS中的filterFilter函数进行过滤
AngularJS中有一个filterFilter函数用来对集合过滤,非常方便. 源代码大致如下: function filterFilter(){ return function(aray, exp ...
- selenium+python自动化78-autoit参数化与批量上传
前言 前一篇autoit实现文件上传打包成.exe可执行文件后,每次只能传固定的那个图片,我们实际测试时候希望传不同的图片. 这样每次调用的时候,在命令行里面加一个文件路径的参数就行. 一.命令行参数 ...