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第十五题的更多相关文章

  1. 看雪CTF第十四题

    from z3 import * dest=[] s = Solver() data = [, , , , , , , , , , , , , , , , , , , , , , , , , , , ...

  2. 看雪CTF第十题

    __int64 sub_140006F50() { __int64 v0; // r8@1 __int64 v1; // r9@1 signed __int64 len; // rax@1 __int ...

  3. 2019看雪CTF 晋级赛Q2第四题wp

    上次参加2019看雪CTF 晋级赛Q2卡在了这道题上,虽然逆出算法,但是方程不会解,哈哈哈哈,果然数学知识很重要呀,现在记录一下. 首先根据关键信息,根据错误提示字符串定位到这里: 1 int __t ...

  4. 看雪CTF第八题

    IDA查看Exports有3个TlsCallback 只有TlsCallback_2有用 其中创建6个线程用于代码动态解码smc 只有前三个线程有用 分别对check_part1,check_part ...

  5. LeetCode第十五题-找出数组中三数和为0的答案

    3Sum 问题简介: 给定n个整数的数组nums,是否有元素a,b,c在nums中,使a + b + c = 0? 找到数组中所有唯一的三元组,它们的总和为零 注:解决方案集不得包含重复的三元组 例如 ...

  6. leecode第十五题(三数之和)

    class Solution { public: void quick_order(vector<int>& num, int star, int en)//快排 { int st ...

  7. 【leetcode 简单】 第三十五题 环形链表

    给定一个链表,判断链表中是否有环. 进阶: 你能否不使用额外空间解决此题? /** * Definition for singly-linked list. * struct ListNode { * ...

  8. 输出1到最大的N位数 【微软面试100题 第六十五题】

    题目要求: 输入数字n,按顺序输出从1到最大的n位10进制数. 例如,输入3,则输出1.2.3....999(最大的3位数). 参考资料:剑指offer第12题. 题目分析: 如果我们在数字前面补0的 ...

  9. C++异常安全的赋值运算符重载 【微软面试100题 第五十五题】

    题目要求: 类CMyString的声明如下: class CMyString { public: CMyString(char *pData=NULL); CMyString(const CMyStr ...

随机推荐

  1. 使用js在浏览器中禁止右键、审查元素、复制功能

    //禁止右键 document.oncontextmenu = function () { return false } //禁止f12 document.onkeydown = function(e ...

  2. IdentityServer4-参考

    一.Identity Resource 二.API Resource 三.Client 四.GrantValidationResult 五.Profile Service 六.IdentityServ ...

  3. 浅谈CSS和JQuery实现鼠标悬浮图片放大效果

    对于刚刚学习网页前台设计的同学一定对图片的处理非常苦恼,那么这里简单的讲解一下几个图片处理的实例. 以.net为平台,微软的Visual Studio 2013为开发工具,当然前台技术还是采用CSS3 ...

  4. Bootstrap 分页、标签、徽章、超大屏幕、页面标题

    分页(pagination), 是一种无序列表 1.默认的分页(.pagination) 代码示例: <ul class="pagination"> <li> ...

  5. Android MediaPlayer架构 -- 前言小知识点(一)

    在Android中可以使用MediaPlayer+SurfaceView来实现一个简单的多媒体播放器. 一  构造函数 java MediaPlayer class 的源码位置:frameworks\ ...

  6. 多个gridSelect引用同一个dizData

    independence设置为true,如果不设置,下拉没有数据.

  7. Windows平台交叉编译Arm Linux平台的QT5.7库

    1.准备交叉编译环境 环境说明:Windows 7 64位 此过程需要: (1)Qt库开源代码,我使用的是5.7.0版本: (2)Perl语言环境5.12版本以上: (3)Python语言环境 2.7 ...

  8. 使用 IntraWeb (29) - 基本控件之 TIWAutherList、TIWAutherINI、TIWAutherEvent

    TIWAutherList //通过一组户名与密码验证登陆 TIWAutherINI //通过记录户名与密码信息的 #Auth.ini 文件验证登陆 TIWAutherEvent //通过其 OnCh ...

  9. [Functional Programming] From simple implementation to Currying to Partial Application

    Let's say we want to write a most simple implementation 'avg' function: const avg = list => { let ...

  10. 阿里云服务器CentOS7怎么分区格式化/挂载硬盘

    一.在阿里云上购买了服务器的硬盘后就可以操作了,先看看硬盘情况: 硬盘vda是系统盘:vdb是在阿里云后台购买的另一块硬盘. 第一次使用要分区:fdisk /dev/vdb1 在提示符下依次输入:n+ ...