【wp】2020XCTF_逆向
发布日期:2021-05-09 01:03:04 浏览次数:20 分类:博客文章

本文共 94290 字,大约阅读时间需要 314 分钟。

前几天的XCTF最后一场终于打完了,三场比赛下来对逆向部分的大概感觉是从第一场的啥都不会做到后来的终于能有参与度了TvT,至少后两场的题目都是pc逆向,虽然特殊架构但好歹能做(tcl

本文是三场XCTF所有逆向题目的wp+复现整理。赛中拿到了7/10的flag,很多是跟着队里的大佬做出来的(tqltql),这边就试着独立复现一下,至少打完应该长长记性(

官方wp出了,借助wp提供的思路复现填坑√。(9/10)

1220那场的apk逆向还没复现完,因为博客要更新点配置所以就先放上来了qvq。

比赛官网:

官方wp:


[12.20] 华为云专场

Weird_lua

根据官方wp,说是改了loadbyte和opcode顺序。这里假装没看过wp,看能不能分析出怎么看出来是这里魔改的。

首先看附件是luacheck_license_out.lua,可以用file分别看一下

单独运行./lua,可以看到版本号是5.3.3

这里运行目标文件的方式是./lua ./check_license_out.lua

感觉这个.lua文件实际可能是.luac文件,即lua字节码文件。

于是先随便写一个lua源码(除了不知名check以外,大致对目标文件check_license_out.lua进行复刻),用v5.3.3的lua(可以在lua官网下载)编译成字节码,看看正常版和魔改版两个文件的区别。

-- test.luafunction check(s)    local len=#s    if len==42 then        return "Check!"    else         return "length error"    end end io.write("input: ")str=io.read()print(check(str))

lua test.lua运行:(注意这里是用正常的lua解释器而不是题目给的)

然后用luac -o test.luac test.lua得到test.luac字节码文件,然后把check_license_out.lua(上)和test.luac(下)用010Editor打开对比十六进制码。

可以看到,除了最开始的一字节为"1B"和"1C"以外,其余文件头中不同的字节都相差较大,感觉是某个特定的换算关系,位置看起来却没什么规律。

定位到lua-5.3.3/src文件夹中,有两个执行luac dump相关操作的头文件,分别是ldump.h(save precompiled Lua chunks)和lundump.h(load precompiled Lua chunks),这里猜测是用于load的lundump.c被魔改。

从这里(类似于主函数的函数)开始是整个的load步骤,可以看到上面对比中第一个差距比较大的字节是在0004h的位置,应该是在checkHeader部分,跟进这个checkHeader()函数。

237行是check文件头的"\x1bLua"部分(题目开头0x1c这个很容易看出就是硬改),而下面开始是check LUAC_VERSION即lua的版本号,本来应该是0x53,但是题目文件对应位置是0xAC,而且往后对照可以看到,不同字节部分都用了LoadByte()函数,猜测是在加载字节的时候有魔改,至于具体怎么魔改那可能得靠直觉了吧(。),大概能靠猜?(或者看lua文件的反编译= =

在官方wp里,魔改的具体信息已经给了:

static lu_byte LoadByte (LoadState *S) {    lu_byte x;    LoadVar(S, x);    //x ^= 0xff; 此行为魔改部分    return x;}

跟着官方wp走不通的思路

本部分可跳过,最后因为刚刚接触lua,对这个语言不熟悉,卡在创造不出帖子里提到的 “用于 dump 的函数,尽量覆盖所有的指令操作,否则只能提取出已有的指令” 的lua函数,帖子里的test无法在5.3版本的lua中提取出所有字节码,需要自己动手创造(。

因为这里LoadByte的魔改会影响到下一步的opcode顺序还原,所以要先把这些错误字节xor回去。

又因为LoadByte的更改只影响到部分字节,我们并不清楚具体哪些字节遭到了祸害,所以想到了一个比较笨的方法就是重新编译一个lua解释器,这样我们就有了opcode顺序魔改前的解释器和魔改后的解释器(题目所给的)。

(如果有师傅有更好的办法求告知><)

将之前的lua-5.3.3文件夹复制到一个新路径,cd到文件夹中,执行make clean将文件中上一次的编译临时文件清空。其实理论上说不复制出来也应该不会影响到原来的lua,但为了保险起见还是这么干吧。

然后把lua-5.3.3/src/ldump.c(注意文件名!!)的52-56行即DumpByte()函数部分改为:

static void DumpByte (int y, DumpState *D) {  lu_byte x = (lu_byte)y;  x^=0xff;//增加此行  DumpVar(x, D);}

保存,退回到lua-5.3.3根目录下,在WSL中用make linux编译。

至于为什么是改ldump.c而不是改官方wp指定魔改的lundump.c,因为ldump.c的作用是保存字节码,而lundump.c的作用是加载字节码。这里参照文中的方法进行还原。

帖子里的lua版本为v5.1.5,对这里v5.3.3并不能直接用(opcode有增加+有些5.3中新增的指令),需要对源码(Check_OpCode/check_opcode.lua)做一些修改,修改后的文件如下。

-- check_opcode.lualocal bit = require('bit')local test = require('test')-- 加载用正常 lua 的 dump 文件local fp = io.open("test.luac","rb")local ori_data = fp:read("*all")fp:close()-- print('data len '.. #data)-- print('ori_data len ' .. #ori_data)local ori_op_name = {    "MOVE",    "LOADK",    "LOADKX",    "LOADBOOL",    "LOADNIL",    "GETUPVAL",    "GETTABUP",    "GETTABLE",    "SETTABUP",    "SETUPVAL",    "SETTABLE",    "NEWTABLE",    "SELF",    "ADD",    "SUB",    "MUL",    "MOD",    "POW",    "DIV",    "IDIV",    "BAND",    "BOR",    "BXOR",    "SHL",    "SHR",    "UNM",    "BNOT",    "NOT",    "LEN",    "CONCAT",    "JMP",    "EQ",    "LT",    "LE",    "TEST",    "TESTSET",    "CALL",    "TAILCALL",    "RETURN",    "FORLOOP",    "FORPREP",    "TFORCALL",    "TFORLOOP",    "SETLIST",    "CLOSURE",    "VARARG",    "EXTRAARG",}local data = string.dump(test)	-- dumplocal new_op = {}-- 用目标 lua 和正常 lua 的 dump 数据对比for i = 2, #data do	local by_ori = string.byte(ori_data,i)	local by_new = string.byte(data,i)	if by_ori ~= by_new then        -- 字节码被xor 0xff处理        local op_name = ori_op_name[by_ori + 1]        local op_idx = by_new        -- if by_ori>47 then        --     op_name = ori_op_name[(by_ori~0xff) + 1]        --     op_idx = (by_new~0xff)        -- end        if op_name~=nil then            if new_op[op_name]~=nil and new_op[op_name]~=op_idx then                print(op_name,new_op[op_name])            end		    new_op[op_name] = op_idx        end	endendprint("old \t new \t name")local cnt=0for idx, op_name in pairs(ori_op_name) do	local tmp = ''	if new_op[op_name] ~= nil then		tmp = new_op[op_name]        cnt=cnt+1	end	print((idx - 1) .. "\t" .. tmp .. "\t" .. op_name )endprint(cnt)

将题目附件的lua重命名为lua_problem并复制到Check_OpCode文件夹中,同时将刚刚xor了字节的lua-5.3.3/src/lua也复制过来。

P.S. 由于帖子中给出的test.lua与前文中最开始用到的lua文件重名,故以下test.lua均代表为帖子中的lua文件,前文中的test.lua不再被引用。

依次在WSL中运行:

./lua dump_test_luac.lua./lua_problem check_opcode.lua

(然后发现写不出能覆盖所有字节码的test(),遂放弃该思路。

自创思路

我们知道在lua源码里,opcode是按顺序存放在lopcodes.hlopcodes.c里的,故顺序魔改其实可以追踪lua解释器在ida中的反编译即可。(这里的lua就是题目给的那个。

源码中的opcode处:

lua加载进ida中,用shift+F12提取字符串,并用ctrl+F搜索“MOVE”

双击,按x找到交叉引用

这里就是魔改后的opcode顺序!

那么我们现在就掌握了所有魔改的信息,开始恢复还原。

这里用到的是著名的lua反汇编/反编译项目,由于lua解释器被魔改(xor 0xff和opcode顺序),所以我们需要在原安装步骤的基础上做些调整。

git clone https://github.com/viruscamp/luadeccd luadecgit submodule update --init lua-5.3cd lua-5.3###### 此处在make之前需要调整源码!make linuxcd ../luadecmake LUAVER=5.3

调整源码如下:

/* luadec/lua-5.3/src/lopcodes.h 原line165-232 */typedef enum {OP_MOVE,OP_LOADK,OP_LOADKX,OP_LOADBOOL,OP_LOADNIL,OP_GETUPVAL,OP_LT,OP_RETURN,OP_GETTABLE,OP_TESTSET,OP_SELF,OP_NEWTABLE,OP_LE,OP_ADD,OP_SUB,OP_MUL,OP_MOD,OP_POW,OP_DIV,OP_IDIV,OP_BAND,OP_BOR,OP_BXOR,OP_SHL,OP_SHR,OP_UNM,OP_BNOT,OP_NOT,OP_LEN,OP_GETTABUP,OP_JMP,OP_TEST,OP_SETTABUP,OP_TFORCALL,OP_FORPREP,OP_EXTRAARG,OP_CALL,OP_FORLOOP,OP_SETLIST,OP_CONCAT,OP_TAILCALL,OP_TFORLOOP,OP_VARARG,OP_SETTABLE,OP_SETUPVAL,OP_CLOSURE,OP_EQ,} OpCode;
/* luadec/lua-5.3/src/lopcodes.c 原line20-69 */LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {  "MOVE",  "LOADK",  "LOADKX",  "LOADBOOL",  "LOADNIL",  "GETUPVAL",  "LT",  "RETURN",  "GETTABLE",  "TESTSET",  "SELF",  "NEWTABLE",  "LE",  "ADD",  "SUB",  "MUL",  "MOD",  "POW",  "DIV",  "IDIV",  "BAND",  "BOR",  "BXOR",  "SHL",  "SHR",  "UNM",  "BNOT",  "NOT",  "LEN",  "GETTABUP",  "JMP",  "TEST",  "SETTABUP",  "TFORCALL",  "FORPREP",  "EXTRAARG",  "CALL",  "FORLOOP",  "SETLIST",  "CONCAT",  "TAILCALL",  "TFORLOOP",  "VARARG",  "SETTABLE",  "SETUPVAL",  "CLOSURE",  "EQ",  NULL};
/* luadec/lua-5.3/src/lundump.c 原line60-64 */static lu_byte LoadByte (LoadState *S) {  lu_byte x;  LoadVar(S, x);  x^=0xff;  return x;}
/* luadec/lua-5.3/src/Makefile 原line9 */CC= gcc -std=gnu99 -m32//因为题目所给的lua解释器为32位
/* luadec/luadec/Makefile 原line16 */CC= gcc -m32//同上

修改完源码后接着make。

走完流程后把check_license_out.lua的第一个字节改为"\x1b",以对上LUA_SIGNATURE,并复制到luadec/luadec文件夹中。

然后在luadec/luadec下运行:

./luadec -dis check_license_out.lua > discheck

(如wp所说,反编译会报错,只能反汇编,估计是乱魔改的原因哈哈哈哈。

得到反汇编的discheck。

; Disassembled using luadec 2.2 rev: 895d923 for Lua 5.3 from https://github.com/viruscamp/luadec; Command line: -dis check_license_out.lua ; Function:        0; Defined at line: 0; #Upvalues:       1; #Parameters:     0; Is_vararg:       2; Max Stack Size:  53    0 [-]: __eq      R0 0         ; R0 := closure(Function #0_0)    1 [-]: SETTABUP  U0 K0 R0     ; U0["to_v"] := R0    2 [-]: NEWTABLE  R0 21 0      ; R0 := {} (size = 21,0)    3 [-]: LOADK     R1 K1        ; R1 := 172    4 [-]: LOADK     R2 K2        ; R2 := 25    5 [-]: LOADK     R3 K3        ; R3 := 60    6 [-]: LOADK     R4 K4        ; R4 := 95    7 [-]: LOADK     R5 K5        ; R5 := 5    8 [-]: LOADK     R6 K6        ; R6 := 27    9 [-]: LOADK     R7 K7        ; R7 := 49   10 [-]: LOADK     R8 K8        ; R8 := 58   11 [-]: LOADK     R9 K9        ; R9 := 171   12 [-]: LOADK     R10 K5       ; R10 := 5   13 [-]: LOADK     R11 K10      ; R11 := 253   14 [-]: LOADK     R12 K11      ; R12 := 45   15 [-]: LOADK     R13 K12      ; R13 := 87   16 [-]: LOADK     R14 K13      ; R14 := 246   17 [-]: LOADK     R15 K14      ; R15 := 197   18 [-]: LOADK     R16 K15      ; R16 := 12   19 [-]: LOADK     R17 K16      ; R17 := 97   20 [-]: LOADK     R18 K17      ; R18 := 234   21 [-]: LOADK     R19 K18      ; R19 := 159   22 [-]: LOADK     R20 K19      ; R20 := 119   23 [-]: LOADK     R21 K20      ; R21 := 157   24 [-]: LOADK     R22 K21      ; R22 := 169   25 [-]: LOADK     R23 K22      ; R23 := 121   26 [-]: LOADK     R24 K23      ; R24 := 54   27 [-]: LOADK     R25 K24      ; R25 := 242   28 [-]: (null)    R0 25 1      ; R0[0] to R0[24] := R1 to R25 ; R(a)[(c-1)*FPF+i] := R(a+i), 1 <= i <= b, a=0, b=25, c=1, FPF=50   29 [-]: NEWTABLE  R1 21 0      ; R1 := {} (size = 21,0)   30 [-]: LOADK     R2 K25       ; R2 := 94   31 [-]: LOADK     R3 K26       ; R3 := 117   32 [-]: LOADK     R4 K27       ; R4 := 57   33 [-]: LOADK     R5 K28       ; R5 := 37   34 [-]: LOADK     R6 K23       ; R6 := 54   35 [-]: LOADK     R7 K29       ; R7 := 110   36 [-]: LOADK     R8 K30       ; R8 := 15   37 [-]: LOADK     R9 K31       ; R9 := 223   38 [-]: LOADK     R10 K32      ; R10 := 163   39 [-]: LOADK     R11 K33      ; R11 := 133   40 [-]: LOADK     R12 K34      ; R12 := 99   41 [-]: LOADK     R13 K35      ; R13 := 237   42 [-]: LOADK     R14 K36      ; R14 := 8   43 [-]: LOADK     R15 K37      ; R15 := 128   44 [-]: LOADK     R16 K6       ; R16 := 27   45 [-]: LOADK     R17 K23      ; R17 := 54   46 [-]: LOADK     R18 K38      ; R18 := 233   47 [-]: LOADK     R19 K39      ; R19 := 181   48 [-]: LOADK     R20 K24      ; R20 := 242   49 [-]: LOADK     R21 K40      ; R21 := 55   50 [-]: LOADK     R22 K41      ; R22 := 230   51 [-]: LOADK     R23 K42      ; R23 := 62   52 [-]: LOADK     R24 K43      ; R24 := 42   53 [-]: LOADK     R25 K44      ; R25 := 252   54 [-]: LOADK     R26 K45      ; R26 := 116   55 [-]: (null)    R1 25 1      ; R1[0] to R1[24] := R2 to R26 ; R(a)[(c-1)*FPF+i] := R(a+i), 1 <= i <= b, a=1, b=25, c=1, FPF=50   56 [-]: NEWTABLE  R2 48 0      ; R2 := {} (size = 48,0)   57 [-]: LOADK     R3 K46       ; R3 := 81   58 [-]: LOADK     R4 K47       ; R4 := 138   59 [-]: LOADK     R5 K48       ; R5 := 85   60 [-]: LOADK     R6 K49       ; R6 := 142   61 [-]: LOADK     R7 K50       ; R7 := 185   62 [-]: LOADK     R8 K51       ; R8 := 35   63 [-]: LOADK     R9 K52       ; R9 := 229   64 [-]: LOADK     R10 K53      ; R10 := 83   65 [-]: LOADK     R11 K36      ; R11 := 8   66 [-]: LOADK     R12 K54      ; R12 := 225   67 [-]: LOADK     R13 K55      ; R13 := 92   68 [-]: LOADK     R14 K31      ; R14 := 223   69 [-]: LOADK     R15 K56      ; R15 := 222   70 [-]: LOADK     R16 K57      ; R16 := 47   71 [-]: LOADK     R17 K58      ; R17 := 182   72 [-]: LOADK     R18 K59      ; R18 := 158   73 [-]: LOADK     R19 K60      ; R19 := 17   74 [-]: LOADK     R20 K61      ; R20 := 74   75 [-]: LOADK     R21 K62      ; R21 := 34   76 [-]: LOADK     R22 K63      ; R22 := 100   77 [-]: LOADK     R23 K64      ; R23 := 43   78 [-]: LOADK     R24 K65      ; R24 := 103   79 [-]: LOADK     R25 K66      ; R25 := 102   80 [-]: LOADK     R26 K67      ; R26 := 147   81 [-]: LOADK     R27 K35      ; R27 := 237   82 [-]: LOADK     R28 K68      ; R28 := 88   83 [-]: LOADK     R29 K69      ; R29 := 73   84 [-]: LOADK     R30 K70      ; R30 := 28   85 [-]: LOADK     R31 K71      ; R31 := 224   86 [-]: LOADK     R32 K72      ; R32 := 23   87 [-]: LOADK     R33 K73      ; R33 := 44   88 [-]: LOADK     R34 K74      ; R34 := 40   89 [-]: LOADK     R35 K75      ; R35 := 154   90 [-]: LOADK     R36 K76      ; R36 := 127   91 [-]: LOADK     R37 K77      ; R37 := 16   92 [-]: LOADK     R38 K21      ; R38 := 169   93 [-]: LOADK     R39 K78      ; R39 := 160   94 [-]: LOADK     R40 K79      ; R40 := 118   95 [-]: LOADK     R41 K80      ; R41 := 51   96 [-]: LOADK     R42 K81      ; R42 := 194   97 [-]: LOADK     R43 K82      ; R43 := 31   98 [-]: LOADK     R44 K83      ; R44 := 68   99 [-]: LOADK     R45 K84      ; R45 := 89  100 [-]: LOADK     R46 K85      ; R46 := 65  101 [-]: LOADK     R47 K86      ; R47 := 162  102 [-]: LOADK     R48 K87      ; R48 := 13  103 [-]: LOADK     R49 K88      ; R49 := 141  104 [-]: LOADK     R50 K89      ; R50 := 0  105 [-]: LOADK     R51 K90      ; R51 := 244  106 [-]: LOADK     R52 K19      ; R52 := 119  107 [-]: (null)    R2 50 1      ; R2[0] to R2[49] := R3 to R52 ; R(a)[(c-1)*FPF+i] := R(a+i), 1 <= i <= b, a=2, b=50, c=1, FPF=50  108 [-]: LOADK     R3 K91       ; R3 := 161  109 [-]: LOADK     R4 K92       ; R4 := 198  110 [-]: LOADK     R5 K93       ; R5 := 228  111 [-]: LOADK     R6 K4        ; R6 := 95  112 [-]: LOADK     R7 K94       ; R7 := 10  113 [-]: LOADK     R8 K95       ; R8 := 78  114 [-]: LOADK     R9 K28       ; R9 := 37  115 [-]: LOADK     R10 K22      ; R10 := 121  116 [-]: LOADK     R11 K96      ; R11 := 236  117 [-]: LOADK     R12 K97      ; R12 := 59  118 [-]: LOADK     R13 K3       ; R13 := 60  119 [-]: LOADK     R14 K98      ; R14 := 91  120 [-]: LOADK     R15 K99      ; R15 := 146  121 [-]: LOADK     R16 K100     ; R16 := 46  122 [-]: LOADK     R17 K101     ; R17 := 77  123 [-]: LOADK     R18 K102     ; R18 := 218  124 [-]: LOADK     R19 K103     ; R19 := 66  125 [-]: LOADK     R20 K104     ; R20 := 200  126 [-]: LOADK     R21 K105     ; R21 := 61  127 [-]: LOADK     R22 K106     ; R22 := 241  128 [-]: LOADK     R23 K107     ; R23 := 70  129 [-]: LOADK     R24 K40      ; R24 := 55  130 [-]: LOADK     R25 K108     ; R25 := 39  131 [-]: LOADK     R26 K109     ; R26 := 227  132 [-]: LOADK     R27 K43      ; R27 := 42  133 [-]: LOADK     R28 K110     ; R28 := 2  134 [-]: LOADK     R29 K111     ; R29 := 231  135 [-]: LOADK     R30 K112     ; R30 := 235  136 [-]: LOADK     R31 K113     ; R31 := 122  137 [-]: LOADK     R32 K114     ; R32 := 135  138 [-]: LOADK     R33 K115     ; R33 := 152  139 [-]: LOADK     R34 K116     ; R34 := 137  140 [-]: LOADK     R35 K117     ; R35 := 173  141 [-]: LOADK     R36 K118     ; R36 := 232  142 [-]: LOADK     R37 K119     ; R37 := 101  143 [-]: LOADK     R38 K120     ; R38 := 75  144 [-]: LOADK     R39 K38      ; R39 := 233  145 [-]: LOADK     R40 K121     ; R40 := 21  146 [-]: LOADK     R41 K44      ; R41 := 252  147 [-]: LOADK     R42 K30      ; R42 := 15  148 [-]: LOADK     R43 K33      ; R43 := 133  149 [-]: LOADK     R44 K122     ; R44 := 111  150 [-]: LOADK     R45 K123     ; R45 := 205  151 [-]: LOADK     R46 K27      ; R46 := 57  152 [-]: LOADK     R47 K124     ; R47 := 132  153 [-]: LOADK     R48 K125     ; R48 := 187  154 [-]: LOADK     R49 K126     ; R49 := 96  155 [-]: LOADK     R50 K7       ; R50 := 49  156 [-]: LOADK     R51 K127     ; R51 := 124  157 [-]: LOADK     R52 K128     ; R52 := 86  158 [-]: (null)    R2 50 2      ; R2[50] to R2[99] := R3 to R52 ; R(a)[(c-1)*FPF+i] := R(a+i), 1 <= i <= b, a=2, b=50, c=2, FPF=50  159 [-]: LOADK     R3 K129      ; R3 := 19  160 [-]: LOADK     R4 K130      ; R4 := 188  161 [-]: LOADK     R5 K131      ; R5 := 80  162 [-]: LOADK     R6 K132      ; R6 := 213  163 [-]: LOADK     R7 K133      ; R7 := 106  164 [-]: LOADK     R8 K134      ; R8 := 214  165 [-]: LOADK     R9 K135      ; R9 := 203  166 [-]: LOADK     R10 K136     ; R10 := 177  167 [-]: LOADK     R11 K137     ; R11 := 56  168 [-]: LOADK     R12 K138     ; R12 := 104  169 [-]: LOADK     R13 K139     ; R13 := 82  170 [-]: LOADK     R14 K29      ; R14 := 110  171 [-]: LOADK     R15 K140     ; R15 := 196  172 [-]: LOADK     R16 K141     ; R16 := 113  173 [-]: LOADK     R17 K142     ; R17 := 155  174 [-]: LOADK     R18 K143     ; R18 := 170  175 [-]: LOADK     R19 K144     ; R19 := 150  176 [-]: LOADK     R20 K26      ; R20 := 117  177 [-]: LOADK     R21 K145     ; R21 := 26  178 [-]: LOADK     R22 K146     ; R22 := 140  179 [-]: LOADK     R23 K147     ; R23 := 144  180 [-]: LOADK     R24 K148     ; R24 := 11  181 [-]: LOADK     R25 K1       ; R25 := 172  182 [-]: LOADK     R26 K149     ; R26 := 67  183 [-]: LOADK     R27 K150     ; R27 := 209  184 [-]: LOADK     R28 K151     ; R28 := 125  185 [-]: LOADK     R29 K23      ; R29 := 54  186 [-]: LOADK     R30 K8       ; R30 := 58  187 [-]: LOADK     R31 K37      ; R31 := 128  188 [-]: LOADK     R32 K152     ; R32 := 204  189 [-]: LOADK     R33 K153     ; R33 := 186  190 [-]: LOADK     R34 K154     ; R34 := 199  191 [-]: LOADK     R35 K155     ; R35 := 189  192 [-]: LOADK     R36 K156     ; R36 := 208  193 [-]: LOADK     R37 K157     ; R37 := 239  194 [-]: LOADK     R38 K158     ; R38 := 143  195 [-]: LOADK     R39 K159     ; R39 := 249  196 [-]: LOADK     R40 K13      ; R40 := 246  197 [-]: LOADK     R41 K160     ; R41 := 1  198 [-]: LOADK     R42 K161     ; R42 := 139  199 [-]: LOADK     R43 K162     ; R43 := 33  200 [-]: LOADK     R44 K12      ; R44 := 87  201 [-]: LOADK     R45 K163     ; R45 := 64  202 [-]: LOADK     R46 K45      ; R46 := 116  203 [-]: LOADK     R47 K164     ; R47 := 84  204 [-]: LOADK     R48 K165     ; R48 := 254  205 [-]: LOADK     R49 K166     ; R49 := 126  206 [-]: LOADK     R50 K167     ; R50 := 202  207 [-]: LOADK     R51 K168     ; R51 := 148  208 [-]: LOADK     R52 K169     ; R52 := 76  209 [-]: (null)    R2 50 3      ; R2[100] to R2[149] := R3 to R52 ; R(a)[(c-1)*FPF+i] := R(a+i), 1 <= i <= b, a=2, b=50, c=3, FPF=50  210 [-]: LOADK     R3 K170      ; R3 := 247  211 [-]: LOADK     R4 K171      ; R4 := 115  212 [-]: LOADK     R5 K172      ; R5 := 109  213 [-]: LOADK     R6 K173      ; R6 := 3  214 [-]: LOADK     R7 K174      ; R7 := 238  215 [-]: LOADK     R8 K175      ; R8 := 114  216 [-]: LOADK     R9 K176      ; R9 := 156  217 [-]: LOADK     R10 K177     ; R10 := 195  218 [-]: LOADK     R11 K32      ; R11 := 163  219 [-]: LOADK     R12 K18      ; R12 := 159  220 [-]: LOADK     R13 K178     ; R13 := 52  221 [-]: LOADK     R14 K179     ; R14 := 36  222 [-]: LOADK     R15 K180     ; R15 := 245  223 [-]: LOADK     R16 K181     ; R16 := 240  224 [-]: LOADK     R17 K182     ; R17 := 63  225 [-]: LOADK     R18 K183     ; R18 := 153  226 [-]: LOADK     R19 K184     ; R19 := 166  227 [-]: LOADK     R20 K185     ; R20 := 167  228 [-]: LOADK     R21 K186     ; R21 := 175  229 [-]: LOADK     R22 K187     ; R22 := 9  230 [-]: LOADK     R23 K188     ; R23 := 151  231 [-]: LOADK     R24 K9       ; R24 := 171  232 [-]: LOADK     R25 K189     ; R25 := 216  233 [-]: LOADK     R26 K190     ; R26 := 207  234 [-]: LOADK     R27 K191     ; R27 := 179  235 [-]: LOADK     R28 K192     ; R28 := 72  236 [-]: LOADK     R29 K193     ; R29 := 176  237 [-]: LOADK     R30 K194     ; R30 := 48  238 [-]: LOADK     R31 K195     ; R31 := 178  239 [-]: LOADK     R32 K20      ; R32 := 157  240 [-]: LOADK     R33 K196     ; R33 := 20  241 [-]: LOADK     R34 K39      ; R34 := 181  242 [-]: LOADK     R35 K197     ; R35 := 149  243 [-]: LOADK     R36 K198     ; R36 := 53  244 [-]: LOADK     R37 K199     ; R37 := 184  245 [-]: LOADK     R38 K200     ; R38 := 4  246 [-]: LOADK     R39 K201     ; R39 := 136  247 [-]: LOADK     R40 K202     ; R40 := 165  248 [-]: LOADK     R41 K203     ; R41 := 217  249 [-]: LOADK     R42 K204     ; R42 := 50  250 [-]: LOADK     R43 K205     ; R43 := 190  251 [-]: LOADK     R44 K206     ; R44 := 191  252 [-]: LOADK     R45 K207     ; R45 := 192  253 [-]: LOADK     R46 K208     ; R46 := 193  254 [-]: LOADK     R47 K209     ; R47 := 98  255 [-]: LOADK     R48 K210     ; R48 := 215  256 [-]: LOADK     R49 K42      ; R49 := 62  257 [-]: LOADK     R50 K211     ; R50 := 112  258 [-]: LOADK     R51 K212     ; R51 := 38  259 [-]: LOADK     R52 K213     ; R52 := 90  260 [-]: (null)    R2 50 4      ; R2[150] to R2[199] := R3 to R52 ; R(a)[(c-1)*FPF+i] := R(a+i), 1 <= i <= b, a=2, b=50, c=4, FPF=50  261 [-]: LOADK     R3 K214      ; R3 := 123  262 [-]: LOADK     R4 K215      ; R4 := 105  263 [-]: LOADK     R5 K25       ; R5 := 94  264 [-]: LOADK     R6 K216      ; R6 := 221  265 [-]: LOADK     R7 K34       ; R7 := 99  266 [-]: LOADK     R8 K217      ; R8 := 201  267 [-]: LOADK     R9 K218      ; R9 := 206  268 [-]: LOADK     R10 K219     ; R10 := 251  269 [-]: LOADK     R11 K220     ; R11 := 14  270 [-]: LOADK     R12 K221     ; R12 := 211  271 [-]: LOADK     R13 K222     ; R13 := 220  272 [-]: LOADK     R14 K223     ; R14 := 131  273 [-]: LOADK     R15 K224     ; R15 := 212  274 [-]: LOADK     R16 K225     ; R16 := 130  275 [-]: LOADK     R17 K226     ; R17 := 134  276 [-]: LOADK     R18 K10      ; R18 := 253  277 [-]: LOADK     R19 K227     ; R19 := 120  278 [-]: LOADK     R20 K228     ; R20 := 145  279 [-]: LOADK     R21 K229     ; R21 := 18  280 [-]: LOADK     R22 K230     ; R22 := 219  281 [-]: LOADK     R23 K231     ; R23 := 79  282 [-]: LOADK     R24 K232     ; R24 := 129  283 [-]: LOADK     R25 K15      ; R25 := 12  284 [-]: LOADK     R26 K233     ; R26 := 93  285 [-]: LOADK     R27 K5       ; R27 := 5  286 [-]: LOADK     R28 K234     ; R28 := 183  287 [-]: LOADK     R29 K235     ; R29 := 107  288 [-]: LOADK     R30 K236     ; R30 := 71  289 [-]: LOADK     R31 K237     ; R31 := 226  290 [-]: LOADK     R32 K238     ; R32 := 180  291 [-]: LOADK     R33 K239     ; R33 := 24  292 [-]: LOADK     R34 K17      ; R34 := 234  293 [-]: LOADK     R35 K240     ; R35 := 7  294 [-]: LOADK     R36 K241     ; R36 := 108  295 [-]: LOADK     R37 K242     ; R37 := 174  296 [-]: LOADK     R38 K243     ; R38 := 6  297 [-]: LOADK     R39 K11      ; R39 := 45  298 [-]: LOADK     R40 K244     ; R40 := 29  299 [-]: LOADK     R41 K245     ; R41 := 32  300 [-]: LOADK     R42 K246     ; R42 := 168  301 [-]: LOADK     R43 K41      ; R43 := 230  302 [-]: LOADK     R44 K14      ; R44 := 197  303 [-]: LOADK     R45 K247     ; R45 := 41  304 [-]: LOADK     R46 K2       ; R46 := 25  305 [-]: LOADK     R47 K248     ; R47 := 255  306 [-]: LOADK     R48 K249     ; R48 := 164  307 [-]: LOADK     R49 K6       ; R49 := 27  308 [-]: LOADK     R50 K250     ; R50 := 210  309 [-]: LOADK     R51 K251     ; R51 := 248  310 [-]: LOADK     R52 K16      ; R52 := 97  311 [-]: (null)    R2 50 5      ; R2[200] to R2[249] := R3 to R52 ; R(a)[(c-1)*FPF+i] := R(a+i), 1 <= i <= b, a=2, b=50, c=5, FPF=50  312 [-]: LOADK     R3 K252      ; R3 := 250  313 [-]: LOADK     R4 K253      ; R4 := 22  314 [-]: LOADK     R5 K24       ; R5 := 242  315 [-]: LOADK     R6 K254      ; R6 := 243  316 [-]: LOADK     R7 K255      ; R7 := 30  317 [-]: LOADK     R8 K256      ; R8 := 69  318 [-]: (null)    R2 6 6       ; R2[250] to R2[255] := R3 to R8 ; R(a)[(c-1)*FPF+i] := R(a+i), 1 <= i <= b, a=2, b=6, c=6, FPF=50  319 [-]: LOADK     R3 K257      ; R3 := "encrypt"  320 [-]: __eq      R4 1         ; R4 := closure(Function #0_1)  321 [-]: SETTABUP  U0 R3 R4     ; U0[R3] := R4  322 [-]: LOADK     R3 K258      ; R3 := "check_license"  323 [-]: __eq      R4 2         ; R4 := closure(Function #0_2)  324 [-]: SETTABUP  U0 R3 R4     ; U0[R3] := R4  325 [-]: LOADK     R3 K259      ; R3 := "io"  326 [-]: GETTABUP  R3 U0 R3     ; R3 := U0[R3]  327 [-]: LOADK     R4 K260      ; R4 := "write"  328 [-]: GETTABLE  R3 R3 R4     ; R3 := R3[R4]  329 [-]: LOADK     R4 K261      ; R4 := "input: "  330 [-]: CALL      R3 2 1       ;  := R3(R4)  331 [-]: LOADK     R3 K262      ; R3 := "license"  332 [-]: LOADK     R4 K259      ; R4 := "io"  333 [-]: GETTABUP  R4 U0 R4     ; R4 := U0[R4]  334 [-]: LOADK     R5 K263      ; R5 := "read"  335 [-]: GETTABLE  R4 R4 R5     ; R4 := R4[R5]  336 [-]: LOADK     R5 K264      ; R5 := "*l"  337 [-]: CALL      R4 2 2       ; R4 := R4(R5)  338 [-]: SETTABUP  U0 R3 R4     ; U0[R3] := R4  339 [-]: LOADK     R3 K258      ; R3 := "check_license"  340 [-]: GETTABUP  R3 U0 R3     ; R3 := U0[R3]  341 [-]: LOADK     R4 K262      ; R4 := "license"  342 [-]: GETTABUP  R4 U0 R4     ; R4 := U0[R4]  343 [-]: CALL      R3 2 1       ;  := R3(R4)  344 [-]: RETURN    R0 1         ; return ; Function:        0_0; Defined at line: 2; #Upvalues:       1; #Parameters:     1; Is_vararg:       0; Max Stack Size:  10    0 [-]: NEWTABLE  R1 0 0       ; R1 := {} (size = 0,0)    1 [-]: LOADK     R2 K0        ; R2 := 1    2 [-]: GETTABUP  R3 U0 K1     ; R3 := U0["string"]    3 [-]: GETTABLE  R3 R3 K2     ; R3 := R3["len"]    4 [-]: MOVE      R4 R0        ; R4 := R0    5 [-]: CALL      R3 2 2       ; R3 := R3(R4)    6 [-]: LOADK     R4 K0        ; R4 := 1    7 [-]: FORPREP   R2 8         ; R2 -= R4; pc += 8 (goto 16)    8 [-]: LEN       R6 R1        ; R6 := #R1    9 [-]: ADD       R6 R6 K0     ; R6 := R6 + 1   10 [-]: GETTABUP  R7 U0 K1     ; R7 := U0["string"]   11 [-]: GETTABLE  R7 R7 K3     ; R7 := R7["byte"]   12 [-]: MOVE      R8 R0        ; R8 := R0   13 [-]: MOVE      R9 R5        ; R9 := R5   14 [-]: CALL      R7 3 2       ; R7 := R7(R8 to R9)   15 [-]: __mode    R1 R6 R7     ; R1[R6] := R7   16 [-]: (null)    R2 -9        ; R2 += R4; if R2 <= R3 then R5 := R2; PC += -9 , goto 8 end   17 [-]: RETURN    R1 2         ; return R1   18 [-]: RETURN    R0 1         ; return ; Function:        0_1; Defined at line: 15; #Upvalues:       4; #Parameters:     1; Is_vararg:       0; Max Stack Size:  10    0 [-]: GETTABUP  R1 U0 K0     ; R1 := U0["to_v"]    1 [-]: MOVE      R2 R0        ; R2 := R0    2 [-]: CALL      R1 2 2       ; R1 := R1(R2)    3 [-]: NEWTABLE  R2 0 0       ; R2 := {} (size = 0,0)    4 [-]: LOADK     R3 K1        ; R3 := 1    5 [-]: LEN       R4 R1        ; R4 := #R1    6 [-]: LOADK     R5 K1        ; R5 := 1    7 [-]: FORPREP   R3 10        ; R3 -= R5; pc += 10 (goto 18)    8 [-]: GETTABLE  R7 R1 R6     ; R7 := R1[R6]    9 [-]: GETTABUP  R8 U1 R6     ; R8 := U1[R6]   10 [-]: BXOR      R7 R7 R8     ; R7 := R7 ~ R8   11 [-]: __mode    R1 R6 R7     ; R1[R6] := R7   12 [-]: LEN       R7 R2        ; R7 := #R2   13 [-]: ADD       R7 R7 K1     ; R7 := R7 + 1   14 [-]: GETTABLE  R8 R1 R6     ; R8 := R1[R6]   15 [-]: ADD       R8 R8 K1     ; R8 := R8 + 1   16 [-]: GETTABUP  R8 U2 R8     ; R8 := U2[R8]   17 [-]: __mode    R2 R7 R8     ; R2[R7] := R8   18 [-]: (null)    R3 -11       ; R3 += R5; if R3 <= R4 then R6 := R3; PC += -11 , goto 8 end   19 [-]: LOADK     R3 K2        ; R3 := 0   20 [-]: LOADK     R4 K1        ; R4 := 1   21 [-]: LEN       R5 R1        ; R5 := #R1   22 [-]: LOADK     R6 K1        ; R6 := 1   23 [-]: FORPREP   R4 7         ; R4 -= R6; pc += 7 (goto 31)   24 [-]: GETTABLE  R8 R2 R7     ; R8 := R2[R7]   25 [-]: GETTABUP  R9 U3 R7     ; R9 := U3[R7]   26 [-]: __add     0 R8 R9      ; if R8 == R9 then goto 28 else goto 30   27 [-]: JMP       R0 2         ; PC += 2 (goto 30)   28 [-]: ADD       R3 R3 K1     ; R3 := R3 + 1   29 [-]: JMP       R0 1         ; PC += 1 (goto 31)   30 [-]: ADD       R3 R3 K3     ; R3 := R3 + 2   31 [-]: (null)    R4 -8        ; R4 += R6; if R4 <= R5 then R7 := R4; PC += -8 , goto 24 end   32 [-]: LEN       R4 R1        ; R4 := #R1   33 [-]: __add     1 R3 R4      ; if R3 ~= R4 then goto 35 else goto 39   34 [-]: JMP       R0 4         ; PC += 4 (goto 39)   35 [-]: GETTABUP  R4 U0 K4     ; R4 := U0["print"]   36 [-]: LOADK     R5 K5        ; R5 := "bad"   37 [-]: CALL      R4 2 1       ;  := R4(R5)   38 [-]: JMP       R0 3         ; PC += 3 (goto 42)   39 [-]: GETTABUP  R4 U0 K4     ; R4 := U0["print"]   40 [-]: LOADK     R5 K6        ; R5 := "good"   41 [-]: CALL      R4 2 1       ;  := R4(R5)   42 [-]: RETURN    R0 1         ; return ; Function:        0_2; Defined at line: 38; #Upvalues:       1; #Parameters:     1; Is_vararg:       0; Max Stack Size:  3    0 [-]: LEN       R1 R0        ; R1 := #R0    1 [-]: SETTABUP  U0 K0 R1     ; U0["size"] := R1    2 [-]: GETTABUP  R1 U0 K0     ; R1 := U0["size"]    3 [-]: __add     1 R1 K1      ; if R1 ~= 25 then goto 5 else goto 9    4 [-]: JMP       R0 4         ; PC += 4 (goto 9)    5 [-]: GETTABUP  R1 U0 K2     ; R1 := U0["print"]    6 [-]: LOADK     R2 K3        ; R2 := "length error"    7 [-]: CALL      R1 2 1       ;  := R1(R2)    8 [-]: RETURN    R0 1         ; return     9 [-]: GETTABUP  R1 U0 K4     ; R1 := U0["encrypt"]   10 [-]: MOVE      R2 R0        ; R2 := R0   11 [-]: CALL      R1 2 1       ;  := R1(R2)   12 [-]: RETURN    R0 1         ; return

说是反汇编其实还是有一点反编译注释的吼。

根据注释来走就很容易理顺逻辑啦(可以参考),算法用python还原是:

# Function 0_0:  to_v()# Function 0_1:  encrypt()# Function 0_2:  check_license()def to_v(s):    return [ord(c) for c in s]def encrypt(s):    global tb0,tb1,tb2    u1,u2,u3=tb0,tb2,tb1 #这个upvalue对应我也不知道是怎么看出来的,可能靠试吧    l1=to_v(s)    size=len(l1)    l2=[]    for i in range(size):        l1[i]^=u1[i]        l2.append(u2[l1[i]+1])    r3=0    for i in range(size):        if l2[i]==u3[i]:            r3+=1        else:            r3+=2    if r3!=size:        print("bad")    else:        print("good")    returndef check_license(s):    if len(s)!=25:        print("length error")    else:        encrypt(s)    returnif __name__ == '__main__':    tb0=[172, 25, 60, 95, 5, 27, 49, 58, 171, 5, 253, 45, 87, 246, 197, 12, 97, 234, 159, 119, 157, 169, 121, 54, 242]    tb1=[94, 117, 57, 37, 54, 110, 15, 223, 163, 133, 99, 237, 8, 128, 27, 54, 233, 181, 242, 55, 230, 62, 42, 252, 116]    tb2=[81, 138, 85, 142, 185, 35, 229, 83, 8, 225, 92, 223, 222, 47, 182, 158, 17, 74, 34, 100, 43, 103, 102, 147, 237, 88, 73, 28, 224, 23, 44, 40, 154, 127, 16, 169, 160, 118, 51, 194, 31, 68, 89, 65, 162, 13, 141, 0, 244, 119, 161, 198, 228, 95, 10, 78, 37, 121, 236, 59, 60, 91, 146, 46, 77, 218, 66, 200, 61, 241, 70, 55, 39, 227, 42, 2, 231, 235, 122, 135, 152, 137, 173, 232, 101, 75, 233, 21, 252, 15, 133, 111, 205, 57, 132, 187, 96, 49, 124, 86, 19, 188, 80, 213, 106, 214, 203, 177, 56, 104, 82, 110, 196, 113, 155, 170, 150, 117, 26, 140, 144, 11, 172, 67, 209, 125, 54, 58, 128, 204, 186, 199, 189, 208, 239, 143, 249, 246, 1, 139, 33, 87, 64, 116, 84, 254, 126, 202, 148, 76, 247, 115, 109, 3, 238, 114, 156, 195, 163, 159, 52, 36, 245, 240, 63, 153, 166, 167, 175, 9, 151, 171, 216, 207, 179, 72, 176, 48, 178, 157, 20, 181, 149, 53, 184, 4, 136, 165, 217, 50, 190, 191, 192, 193, 98, 215, 62, 112, 38, 90, 123, 105, 94, 221, 99, 201, 206, 251, 14, 211, 220, 131, 212, 130, 134, 253, 120, 145, 18, 219, 79, 129, 12, 93, 5, 183, 107, 71, 226, 180, 24, 234, 7, 108, 174, 6, 45, 29, 32, 168, 230, 197, 41, 25, 255, 164, 27, 210, 248, 97, 250, 22, 242, 243, 30, 69]    print("input: ",end='')    license=input()    check_license(license)

就可以根据逻辑写出exp:

tb0=[172, 25, 60, 95, 5, 27, 49, 58, 171, 5, 253, 45, 87, 246, 197, 12, 97, 234, 159, 119, 157, 169, 121, 54, 242]tb1=[94, 117, 57, 37, 54, 110, 15, 223, 163, 133, 99, 237, 8, 128, 27, 54, 233, 181, 242, 55, 230, 62, 42, 252, 116]tb2=[81, 138, 85, 142, 185, 35, 229, 83, 8, 225, 92, 223, 222, 47, 182, 158, 17, 74, 34, 100, 43, 103, 102, 147, 237, 88, 73, 28, 224, 23, 44, 40, 154, 127, 16, 169, 160, 118, 51, 194, 31, 68, 89, 65, 162, 13, 141, 0, 244, 119, 161, 198, 228, 95, 10, 78, 37, 121, 236, 59, 60, 91, 146, 46, 77, 218, 66, 200, 61, 241, 70, 55, 39, 227, 42, 2, 231, 235, 122, 135, 152, 137, 173, 232, 101, 75, 233, 21, 252, 15, 133, 111, 205, 57, 132, 187, 96, 49, 124, 86, 19, 188, 80, 213, 106, 214, 203, 177, 56, 104, 82, 110, 196, 113, 155, 170, 150, 117, 26, 140, 144, 11, 172, 67, 209, 125, 54, 58, 128, 204, 186, 199, 189, 208, 239, 143, 249, 246, 1, 139, 33, 87, 64, 116, 84, 254, 126, 202, 148, 76, 247, 115, 109, 3, 238, 114, 156, 195, 163, 159, 52, 36, 245, 240, 63, 153, 166, 167, 175, 9, 151, 171, 216, 207, 179, 72, 176, 48, 178, 157, 20, 181, 149, 53, 184, 4, 136, 165, 217, 50, 190, 191, 192, 193, 98, 215, 62, 112, 38, 90, 123, 105, 94, 221, 99, 201, 206, 251, 14, 211, 220, 131, 212, 130, 134, 253, 120, 145, 18, 219, 79, 129, 12, 93, 5, 183, 107, 71, 226, 180, 24, 234, 7, 108, 174, 6, 45, 29, 32, 168, 230, 197, 41, 25, 255, 164, 27, 210, 248, 97, 250, 22, 242, 243, 30, 69]flag=""for i in range(25):    flag+=chr(tb2.index(tb1[i])^tb0[i])print(flag)

得到flag

flag{th15_15_v3r7_c0mm3n}

divination[TO DO]

先用模拟器跑一下,发现是一个输入字符串判断的逻辑。

因为物理机里装了WSL2,所以用的是能兼容Hyper-V的BlueStacks模拟器。

走流程,先用这个工具把将apk解压后文件夹中的classes.dex文件转换成jar文件,再用中的JD-GUI查看反编译出的java源代码。

然后可以看到MainActivity.class这里也有一句“大事不妙”,找到主函数。

看了一下逻辑就是调用libdivination.so(在apk解压后的路径divination/lib/arm64-v8a/libdivination.so),只要返回值为真就行。

所以其实做安卓逆向看so硬逆也能逆出来hhh。

于是现在转去逆so。

关键入口函数显而易见,就是这个跟包同名的函数。

为了方便看反编译代码,按y把a1-a3三个参数的变量类型进行更改(ida无法自动识别。

下边的函数也一目了然。

从后往前看,先拿到目标数组unk_3000:


[12.23] 鲲鹏计算专场

mips

真·送分题,可惜当时要上课没来得及抢一血(下午2点放题绝了

老传统走迷宫

mips架构。

ida反编译以后可以看到

v4是我们输入的字符串,很明显是迷宫逻辑,上下左右用wasd走,迷宫存在dword_100111F0里。

sub_10000744()这个初始函数是用来找起点用的(就是迷宫中3所在的地方,在后面可以看到3其实表示的是当前位置)。

这里也可以看到应该有多个迷宫(dword_10011D10是用来表示第几个迷宫的,且<=2,一个迷宫有225个数)+一个迷宫宽为15=三个迷宫,每个迷宫为15*15。

然后就是下面的四个函数,随便挑一个出来(比如sub_10000D28())可以看到

很明显是个往右走的函数,3表示当前位置,并把上一个当前位置标为1(可走路径)。并且可以看到终点是4,就是说我们要把每个迷宫从3走到4。

dump迷宫数组,写脚本打印迷宫:

aMap=[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 3, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0]for i in range(45):    for j in range(15):        if aMap[i*15+j]==0:            tmp='*'        elif aMap[i*15+j]==1:            tmp='.'        elif aMap[i*15+j]==3:            tmp='@'        else:            tmp='#'        print(tmp,end='')    print()    if i==14 or i==29:        print()

可以看到打印出了三个迷宫,为了看得清楚所以选用几个特定字符打印。

.....**********.....*@*.******.....*.*.******.....*.*.******.....*.*.....**.....*.*****.**.....*.*****.**.....*.*****..*.....*........*.....********#*...........................................................................#sssssssddddddds..*************..*@*....******..*.****.******..*.****.******..*..***.....**..*..*******.**..*..*******.**..*..*****....*..*..*****.**.*..*..*****.****..*......*.*..*..*...........*..***********#*..............................#ssssssssssdddddddddds****************@..**************.*...**********...*.***********.**.********..*.**.*********...**.**************.**************....**************.**************.**************.**************....**************.**************#*#ddssddwddssssssdddssssdddss

走迷宫,然后把路径拼起来,根据提示转md5,get flag。

(有个疑惑哈,第二个迷宫理论上说就算是最短路也有多解?是题目出锅了还是我哪里看漏了= =

(再补一句,题目似乎甚至没要求最短路???神奇.jpg

import hashlibs=b"sssssssdddddddsssssssssssddddddddddsddssddwddssssssdddssssdddss"print("flag{%s}"%hashlib.md5(s).hexdigest())

flag{999ea6aa6c365ab43eec2a0f0e5968d5}

pypy

把题目文件拖进ida,搜索字符串能看到

猜测是pyinstaller打包的文件。

也就是这个题让我突然发现pyinstaller还能打包成elf的,于是比赛结束以后赶紧把之前总结的解包指南更新了:。

走流程解包,得到python源码。

看到这种混淆变量名,果断替换成ida style变量名(。

放一下源码:

# uncompyle6 version 3.7.4# Python bytecode 3.8 (3413)# Decompiled from: Python 2.7.18 (v2.7.18:8d21aa21f2, Apr 20 2020, 13:25:05) [MSC v.1500 64 bit (AMD64)]# Warning: this version of Python has problems handling the Python 3 "byte" type in constants properly.# Embedded file name: main.py# Compiled at: 1995-09-28 00:18:56# Size of source mod 2**32: 257 bytesimport random, codecs, sys, time, pygamefrom pygame.locals import *from collections import dequeSCREEN_WIDTH = 600SCREEN_HEIGHT = 480SIZE = 20LINE_WIDTH = 1flag = 'flag{this is a fake flag}'SCOPE_X = (0, SCREEN_WIDTH // SIZE - 1)SCOPE_Y = (2, SCREEN_HEIGHT // SIZE - 1)FOOD_STYLE_LIST = [(10, (255, 100, 100)), (20, (100, 255, 100)), (30, (100, 100, 255))]LIGHT = (100, 100, 100)DARK = (200, 200, 200)BLACK = (0, 0, 0)RED = (200, 30, 30)BGCOLOR = (40, 40, 60)def print_text(v1, v2, v3, v4, v5, fcolor=(255, 255, 255)):    v6 = v2.render(v5, True, fcolor)    v1.blit(v6, (v3, v4))def init_snake():    v7 = deque()    v7.append((2, SCOPE_Y[0]))    v7.append((1, SCOPE_Y[0]))    v7.append((0, SCOPE_Y[0]))    return v7def create_food(v8):    v9 = random.randint(SCOPE_X[0], SCOPE_X[1])    v10 = random.randint(SCOPE_Y[0], SCOPE_Y[1])    while (v9, v10) in v8:        v9 = random.randint(SCOPE_X[0], SCOPE_X[1])        v10 = random.randint(SCOPE_Y[0], SCOPE_Y[1])    return (     v9, v10)def get_food_style():    return FOOD_STYLE_LIST[random.randint(0, 2)]DEFAULT_KEY = u'Y\xf3\x02\xc3%\x9a\x820\x0b\xbb%\x7f~;\xd2\xdc'def rc4(v11, key=DEFAULT_KEY, skip=1024):    v12 = 0    v13 = bytearray([v14 for v14 in range(256)])    v12 = 0    for v15 in range(256):        v12 = (v12 + v13[v15] + ord(key[(v15 % len(key))])) % 256        v16 = v13[v15]        v17 = v13[v12]        v13[v15] = v13[v12]        v13[v12] = v16    else:        v12 = 0        v18 = 0        v19 = []        if skip > 0:            for v15 in range(skip):                v12 = (v12 + 1) % 256                v18 = (v18 + v13[v12]) % 256                v13[v12], v13[v18] = v13[v18], v13[v12]        for v20 in v11:            v12 = (v12 + 1) % 256            v18 = (v18 + v13[v12]) % 256            v13[v12], v13[v18] = v13[v18], v13[v12]            v21 = v13[((v13[v12] + v13[v18]) % 256)]            v19.append(chr(ord(v20) ^ v21))        else:            return ''.join(v19)def func(v22):    v23 = rc4(v22)    if v23.encode('utf-8').hex() == '275b39c381c28b701ac3972338456022c2ba06c3b04f5501471c47c38ac380c29b72c3b5c38a7ec2a5c2a0':        return 'YOU WIN'    return 'YOU LOSE'def main():    pygame.init()    v24 = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))    pygame.display.set_caption(u'\u8d2a\u5403\u86c7')    v25 = pygame.font.SysFont('SimHei', 24)    v26 = pygame.font.Font(None, 72)    v27, v28 = v26.size('GAME OVER')    v29 = True    v30 = init_snake()    v31 = create_food(v30)    v32 = get_food_style()    v33 = (1, 0)    v34 = True    v35 = False    v36 = 0    v37 = 0.5    v38 = v37    v39 = None    v41 = False    for v40 in pygame.event.get():        if v40.type == QUIT:            sys.exit()        elif v40.type == KEYDOWN:            if v40.key == K_RETURN:                if v34:                    v35 = True                    v34 = False                    v29 = True                    v30 = init_snake()                    v31 = create_food(v30)                    v32 = get_food_style()                    v33 = (1, 0)                    v36 = 0                    v39 = time.time()            elif v40.key == K_SPACE:                if not v34:                    v41 = not v41            elif v40.key in (K_w, K_UP):                if v29:                    v33 = v33[1] or (0, -1)                    v29 = False            elif v40.key in (K_s, K_DOWN):                if v29:                    v33 = v33[1] or (0, 1)                    v29 = False            elif v40.key in (K_a, K_LEFT):                if v29:                    if not v33[0]:                        v33 = (-1, 0)                        v29 = False                    elif v40.key in (K_d, K_RIGHT):                        if v29:                            if not v33[0]:                                v33 = (1, 0)                                v29 = False        else:            v24.fill(BGCOLOR)            for v42 in range(SIZE, SCREEN_WIDTH, SIZE):                pygame.draw.line(v24, BLACK, (v42, SCOPE_Y[0] * SIZE), (v42, SCREEN_HEIGHT), LINE_WIDTH)            else:                for v43 in range(SCOPE_Y[0] * SIZE, SCREEN_HEIGHT, SIZE):                    pygame.draw.line(v24, BLACK, (0, v43), (SCREEN_WIDTH, v43), LINE_WIDTH)                else:                    v44 = v34 or time.time()            if v44 - v39 > v38 and not v41:                v29 = True                v39 = v44                v45 = (v30[0][0] + v33[0], v30[0][1] + v33[1])                if v45 == v31:                    v30.appendleft(v45)                    v36 += v32[0]                    v38 = v37 - 0.03 * (v36 // 100)                    v31 = create_food(v30)                    v32 = get_food_style()                else:                    if SCOPE_X[0] <= v45[0] <= SCOPE_X[1]:                        if SCOPE_Y[0] <= v45[1] <= SCOPE_Y[1]:                            if v45 not in v30:                                v30.appendleft(v45)                                v30.pop()                            else:                                v34 = True                    if not v34:                        pygame.draw.rect(v24, v32[1], (v31[0] * SIZE, v31[1] * SIZE, SIZE, SIZE), 0)                for v46 in v30:                    pygame.draw.rect(v24, DARK, (v46[0] * SIZE + LINE_WIDTH, v46[1] * SIZE + LINE_WIDTH, SIZE - LINE_WIDTH * 2, SIZE - LINE_WIDTH * 2), 0)                else:                    print_text(v24, v25, 30, 7, f"speed: {v36 // 100}")                    print_text(v24, v25, 450, 7, f"score: {v36}")                    if v36 >= 5192296858534827628530496329220096:                        v47 = flag                        print_text(v24, v26, (SCREEN_WIDTH - v27) // 2, (SCREEN_HEIGHT - v28) // 2, func(v47), RED)                    if v34:                        if v35:                            print_text(v24, v26, (SCREEN_WIDTH - v27) // 2, (SCREEN_HEIGHT - v28) // 2, 'GAME OVER', RED)                    pygame.display.update()if __name__ == '__main__':    main()# okay decompiling main.pyc

可以看到最后getflag这里(func())的程序逻辑就一个rc4加密,由rc4的特性可知加密和解密流程相同,故复用程序中的rc4()来得到flag。

uncompyle反编译出来的源码是python3,但是题目本身的源码是python2,注意编码问题。

关于编码问题,可以看:

这里因为反编译做了转换成python3的处理,所以脚本用python3写。

DEFAULT_KEY = u'Y\xf3\x02\xc3%\x9a\x820\x0b\xbb%\x7f~;\xd2\xdc'def rc4(v11, key=DEFAULT_KEY, skip=1024):    v12 = 0    v13 = bytearray([v14 for v14 in range(256)])    v12 = 0    for v15 in range(256):        v12 = (v12 + v13[v15] + ord(key[(v15 % len(key))])) % 256        v16 = v13[v15]        v17 = v13[v12]        v13[v15] = v13[v12]        v13[v12] = v16    else:        v12 = 0        v18 = 0        v19 = []        if skip > 0:            for v15 in range(skip):                v12 = (v12 + 1) % 256                v18 = (v18 + v13[v12]) % 256                v13[v12], v13[v18] = v13[v18], v13[v12]        for v20 in v11:            v12 = (v12 + 1) % 256            v18 = (v18 + v13[v12]) % 256            v13[v12], v13[v18] = v13[v18], v13[v12]            v21 = v13[((v13[v12] + v13[v18]) % 256)]            v19.append(chr(ord(v20) ^ v21))        else:            return ''.join(v19)# def func(v22):#     v23 = rc4(v22)#     if v23.encode('utf-8').hex() == '275b39c381c28b701ac3972338456022c2ba06c3b04f5501471c47c38ac380c29b72c3b5c38a7ec2a5c2a0':#         return 'YOU WIN'#     return 'YOU LOSE'# -=-=-=以上所有为源码中原函数-=-=-=cipher='275b39c381c28b701ac3972338456022c2ba06c3b04f5501471c47c38ac380c29b72c3b5c38a7ec2a5c2a0'flag=bytes.fromhex(cipher).decode('utf-8')print(rc4(flag))

flag{snake_bao_is_really_lucky}

print

官方wp说的是给了一个brainfuck引擎,跟我赛中攻击格式化字符串漏洞的思路完全不一样(。),一开始还以为我想得太偏了XD,然而在复现的时候发现这个brainfuck解释器的原理就是攻击格式化字符串漏洞,学到了学到了。

以下试图从头开始复现。

通过在上搜索setup()中的特殊字符串"%1$.*1$d %2$hn"查到一个github项目,发现其余的字符串与题目中的十分相似,并且pbf_pre.c跟程序逻辑几乎一样,推测是题目的来源。

所以先通过动态调试,把断点设在前面所有的赋值语句之后,用idapython的get_bytes(0x5577FCB50000,16000)提取出progn的内容。

通过printbf项目中的pbf_pre.c源码可以知道progn是int *,故将提取出来的byte对象进行处理,然后按照token.py的逻辑逆向写出由progn反向生成的brainfuck程序。

# token.py from "HexHive/printbf: Brainfuck interpreter inside printf"#!/usr/bin/python# -*- coding: utf-8 -*-import itertoolsimport sysfrom argparse import ArgumentParser__author__ = "Nicholas Carlini 
and Mathias Payer
"__description__ = "Script to tokenize a BF script into a printf interpreter."__version__ = filter(str.isdigit, "$Revision: 1 $")parser = ArgumentParser(description=__description__)parser.add_argument('-v', '--version', action='version', version='%(prog)s {:s}'.format(__version__))parser.add_argument('-t', '--template', type=str, metavar='template filename', help='Filename for the template to use.', required=False, default='bf_pre.c')parser.add_argument('-bf', '--brainfuck', type=str, metavar='bf file', help='BF program', required=True)parser.add_argument('-i', '--input', type=str, metavar='input to bf', help='BF input', required=False, default='')args = parser.parse_args() prog = open(args.brainfuck).read()prog = "".join([x for x in prog if x in "<>+-.,[]"])prog = prog.replace("[-]", "Z")remap = {'<':[1], '>':[2], '+':[3], '-':[4], '.':[5,6], ',':[7,8], '[':[9,10,11], ']':[12], 'Z':[13], 'F':[14], 'B':[15],#,16,17], 'A':[18], }newprog = []progiter = iter(prog)while len(prog): e = prog[0] if e in '<>+-': res = itertools.takewhile(lambda x: x == e, prog) count = len(list(res)) if e == '>': newprog.append(('F',count)) elif e == '<': assert count < 256 newprog.append(('B',65536-count)) elif e == '+': newprog.append(('A',count)) elif e == '-': newprog.append(('A',256-count)) prog = prog[count:] else: newprog.append(e) prog = prog[1:]stack = []index = 2txt = open(args.template).read()txt = txt.replace('###INPUT###', args.input)print txt[0:txt.find('###TOKER###')],for e in newprog: count = 0 if type(e) == type(tuple()): count = e[1] e = e[0] for i,insn in enumerate(remap[e]): print ' progn[%d] = %d;'%(index+i*2,insn) if count != 0: assert i == 0 print ' progn[%d] = %d;'%(index+1,count) if e == '[': # this is a cgoto stack.append(index) elif e == ']': backto = stack.pop() print ' progn[%d] = %d;'%(backto+1,index*4-4) print ' progn[%d] = %d;'%(backto+3,index*4-4) print ' progn[%d] = %d;'%(backto+5,index*4-4) print ' progn[%d] = %d;'%(index+1,(backto-2)*4) # we always increment PC by 1 index += 2*len(remap[e])print txt[txt.find('###TOKER###')+11:],

可以看到实际上就是从progn[2*k]这里看到brainfuck的每一步操作符,而对于"+-><"这四种操作符的数量由progn[2*k+1]给出,故从这些位置即可提取出bf程序的操作符,得到bf程序:

p=b'' # 这里是动态调试提取出的progn字节对象,太长了这里不贴progn=[]for i in range(0,16000,4):    progn.append(int.from_bytes(p[i:i+4],byteorder='little'))# 转化成printbf中的int* progni=2bfCode=""while i
0x7F: bfCode+='-'*(256-progn[i+1]) else: bfCode+='+'*progn[i+1] i+=2 else: print("[-] UknCode "+str(progn[i])+" in progn["+str(i)+"]") i+=2print(bfCode)

得到:

>,>,>,>,>,>,<<<<<[->>>>>>+<<<<<<<+>]<[->+<]>[->>>>>>+<<<<<<<+>]<[->+<]>>[->>>>>>+<<<<<<<<+>>]<<[->>+<<]>>[->>>>>>+<<<<<<<<+>>]<<[->>+<<]>>>[->>>>>>+<<<<<<<<<+>>>]<<<[->>>+<<<]>>>[->>>>>>+<<<<<<<<<+>>>]<<<[->>>+<<<]>>>>[->>>>>>+<<<<<<<<<<+>>>>]<<<<[->>>>+<<<<]>>>>[->>>>>>+<<<<<<<<<<+>>>>]<<<<[->>>>+<<<<]>>>>>[->>>>>>+<<<<<<<<<<<+>>>>>]<<<<<[->>>>>+<<<<<]>>>>>[->>>>>>+<<<<<<<<<<<+>>>>>]<<<<<[->>>>>+<<<<<]>>>>>>[->>>>>>+<<<<<<<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<]>>>>>>[->>>>>>+<<<<<<<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<]>>>>>>>[->>>>>>+<<<<<<<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]>[->>>>>>>>>>>>+<<<<<<<<<<<<<+>]<[->+<]>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<]>>[->>>>>>>>>>>>+<<<<<<<<<<<<<<+>>]<<[->>+<<]>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<+>>>>>>>>>]<<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>>>[->>>>>>>>>>>>+<<<<<<<<<<<<<<<+>>>]<<<[->>>+<<<]>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<+>>>>>>>>>>]<<<<<<<<<<[->>>>>>>>>>+<<<<<<<<<<]>>>>[->>>>>>>>>>>>+<<<<<<<<<<<<<<<<+>>>>]<<<<[->>>>+<<<<]>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<+>>>>>>>>>>>]<<<<<<<<<<<[->>>>>>>>>>>+<<<<<<<<<<<]>>>>>[->>>>>>>>>>>>+<<<<<<<<<<<<<<<<<+>>>>>]<<<<<[->>>>>+<<<<<]>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>]<<<<<<<<<<<<[->>>>>>>>>>>>+<<<<<<<<<<<<]>>>>>>[->>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<]>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>]<<<<<<<<<<<<<[->>>>>>>>>>>>>+<<<<<<<<<<<<<]>[->>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<+>]<[->+<]>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>]<<<<<<<<<<<<<<[->>>>>>>>>>>>>>+<<<<<<<<<<<<<<]>>[->>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<+>>]<<[->>+<<]>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<]>>>[->>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<+>>>]<<<[->>>+<<<]>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<]>>>>[->>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<+>>>>]<<<<[->>>>+<<<<]>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<]>>>>>[->>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<+>>>>>]<<<<<[->>>>>+<<<<<]>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<]>>>>>>[->>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<]>>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<]>[->>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<+>]<[->+<]>>>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<]>>[->>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<+>>]<<[->>+<<]>>>>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<]>>>[->>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>]<<<[->>>+<<<]>>>>>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<]>>>>[->>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>]<<<<[->>>>+<<<<]>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<]>>>>>[->>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>]<<<<<[->>>>>+<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>[->>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<]>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>]<<[->>+<<]>>>>>>>>>[->>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>]<<<<<<<<<[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>>>>>>>>[->>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>[->>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>[->>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<]>>>>>>>>>>[->>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>]<<<<<<<<<<[->>>>>>>>>>+<<<<<<<<<<]>>>>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>]<<<<<[->>>>>+<<<<<]>>>>>>>>>>>>>[->>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>]<<<<<<<<<<<<<[->>>>>>>>>>>>>+<<<<<<<<<<<<<]>>>>>>>>[->>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<]>>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>]<<<[->>>+<<<]>>>>>>>>>>>>>>>>>>>>>>[->>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>]<<[->>+<<]>>>>>>>>>>>>>>>>>>>>>[->>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>[->>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<]>>>>>>>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<]>>>>>>>>>>>>>>>[->>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>[->>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<]>>>>>>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]>>>>>>>>>>>>>>>>>>>>[->>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<]>>>[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>]<<<[->>>+<<<]>>>>>>>>>>>>>>>>>[->>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]---------------------------->[-]+++++>[-]-------------------------------------------------------------------------------------------------->[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<<<<<<<<<<<[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++++++++++++++++++++++++++++++++++++++++++++++++<<<<<<[>>>>>>+<<<<<<[-]]>[>>>>>+<<<<<[-]]>[>>>>+<<<<[-]]>[>>>+<<<[-]]>[>>+<<[-]]>[>+<[-]]>>,>,>,>,>,>,>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]++++++++++++++++++++++++++++++++++++++++++++++++>[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++<<<<<<<<<<<[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[->>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<+>>>>>>>[-]]>[<<<<<<<<+>>>>>>>>[-]]>[<<<<<<<<<+>>>>>>>>>[-]]>[<<<<<<<<<<+>>>>>>>>>>[-]]>[<<<<<<<<<<<+>>>>>>>>>>>[-]]>[<<<<<<<<<<<<+>>>>>>>>>>>>[-]]<<<<<<<<<<<<.

进一步的,为了方便甚至可以直接转化成c程序,最后的处理脚本为:

p=b'' #依旧是太长不贴(progn=[]for i in range(0,16000,4):    progn.append(int.from_bytes(p[i:i+4],byteorder='little'))# 转化成printbf中的int* progni=2indent=0ptr=0print(' '*indent+"#include 
")print(' '*indent+"int main(){")indent+=4print(' '*indent+"char mem[1000000]={0};")while i
0x7F: print(' '*indent+"mem["+str(ptr)+"]-="+str(256-progn[i+1])+";") else: print(' '*indent+"mem["+str(ptr)+"]+="+str(progn[i+1])+";") i+=2 else: print("[-] UknCode "+str(progn[i])+" in progn["+str(i)+"]") i+=2print(' '*indent+"return 0;")indent-=4print(' '*indent+"}")# 直接转化成C程序

得到C程序:

#include 
int main(){ char mem[1000000]={0}; scanf("%c",&mem[1]); scanf("%c",&mem[2]); scanf("%c",&mem[3]); scanf("%c",&mem[4]); scanf("%c",&mem[5]); scanf("%c",&mem[6]); while(mem[1]){ mem[1]-=1; mem[7]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[1]+=1; } while(mem[1]){ mem[1]-=1; mem[7]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[1]+=1; } while(mem[2]){ mem[2]-=1; mem[8]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[2]+=1; } while(mem[2]){ mem[2]-=1; mem[8]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[2]+=1; } while(mem[3]){ mem[3]-=1; mem[9]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[3]+=1; } while(mem[3]){ mem[3]-=1; mem[9]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[3]+=1; } while(mem[4]){ mem[4]-=1; mem[10]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[4]+=1; } while(mem[4]){ mem[4]-=1; mem[10]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[4]+=1; } while(mem[5]){ mem[5]-=1; mem[11]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[5]+=1; } while(mem[5]){ mem[5]-=1; mem[11]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[5]+=1; } while(mem[6]){ mem[6]-=1; mem[12]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[6]+=1; } while(mem[6]){ mem[6]-=1; mem[12]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[6]+=1; } while(mem[7]){ mem[7]-=1; mem[13]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[7]+=1; } while(mem[1]){ mem[1]-=1; mem[13]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[1]+=1; } while(mem[8]){ mem[8]-=1; mem[14]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[8]+=1; } while(mem[2]){ mem[2]-=1; mem[14]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[2]+=1; } while(mem[9]){ mem[9]-=1; mem[15]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[9]+=1; } while(mem[3]){ mem[3]-=1; mem[15]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[3]+=1; } while(mem[10]){ mem[10]-=1; mem[16]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[10]+=1; } while(mem[4]){ mem[4]-=1; mem[16]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[4]+=1; } while(mem[11]){ mem[11]-=1; mem[17]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[11]+=1; } while(mem[5]){ mem[5]-=1; mem[17]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[5]+=1; } while(mem[12]){ mem[12]-=1; mem[18]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[12]+=1; } while(mem[6]){ mem[6]-=1; mem[18]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[6]+=1; } while(mem[13]){ mem[13]-=1; mem[19]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[13]+=1; } while(mem[1]){ mem[1]-=1; mem[19]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[1]+=1; } while(mem[14]){ mem[14]-=1; mem[20]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[14]+=1; } while(mem[2]){ mem[2]-=1; mem[20]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[2]+=1; } while(mem[15]){ mem[15]-=1; mem[21]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[15]+=1; } while(mem[3]){ mem[3]-=1; mem[21]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[3]+=1; } while(mem[16]){ mem[16]-=1; mem[22]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[16]+=1; } while(mem[4]){ mem[4]-=1; mem[22]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[4]+=1; } while(mem[17]){ mem[17]-=1; mem[23]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[17]+=1; } while(mem[5]){ mem[5]-=1; mem[23]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[5]+=1; } while(mem[18]){ mem[18]-=1; mem[24]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[18]+=1; } while(mem[6]){ mem[6]-=1; mem[24]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[6]+=1; } while(mem[19]){ mem[19]-=1; mem[25]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[19]+=1; } while(mem[1]){ mem[1]-=1; mem[25]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[1]+=1; } while(mem[20]){ mem[20]-=1; mem[26]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[20]+=1; } while(mem[2]){ mem[2]-=1; mem[26]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[2]+=1; } while(mem[21]){ mem[21]-=1; mem[27]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[21]+=1; } while(mem[3]){ mem[3]-=1; mem[27]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[3]+=1; } while(mem[22]){ mem[22]-=1; mem[28]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[22]+=1; } while(mem[4]){ mem[4]-=1; mem[28]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[4]+=1; } while(mem[23]){ mem[23]-=1; mem[29]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[23]+=1; } while(mem[5]){ mem[5]-=1; mem[29]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[5]+=1; } while(mem[24]){ mem[24]-=1; mem[30]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[24]+=1; } while(mem[6]){ mem[6]-=1; mem[30]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[6]+=1; } while(mem[2]){ mem[2]-=1; mem[31]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[2]+=1; } while(mem[9]){ mem[9]-=1; mem[31]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[9]+=1; } while(mem[16]){ mem[16]-=1; mem[31]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[16]+=1; } while(mem[23]){ mem[23]-=1; mem[31]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[23]+=1; } while(mem[30]){ mem[30]-=1; mem[31]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[30]+=1; } while(mem[25]){ mem[25]-=1; mem[32]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[25]+=1; } while(mem[20]){ mem[20]-=1; mem[32]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[20]+=1; } while(mem[15]){ mem[15]-=1; mem[32]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[15]+=1; } while(mem[10]){ mem[10]-=1; mem[32]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[10]+=1; } while(mem[5]){ mem[5]-=1; mem[32]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[5]+=1; } while(mem[13]){ mem[13]-=1; mem[33]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[13]+=1; } while(mem[8]){ mem[8]-=1; mem[33]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[8]+=1; } while(mem[3]){ mem[3]-=1; mem[33]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[3]+=1; } while(mem[22]){ mem[22]-=1; mem[33]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[22]+=1; } while(mem[30]){ mem[30]-=1; mem[33]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[30]+=1; } while(mem[7]){ mem[7]-=1; mem[34]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[7]+=1; } while(mem[2]){ mem[2]-=1; mem[34]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[2]+=1; } while(mem[21]){ mem[21]-=1; mem[34]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[21]+=1; } while(mem[28]){ mem[28]-=1; mem[34]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[28]+=1; } while(mem[17]){ mem[17]-=1; mem[34]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[17]+=1; } while(mem[8]){ mem[8]-=1; mem[35]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[8]+=1; } while(mem[15]){ mem[15]-=1; mem[35]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[15]+=1; } while(mem[22]){ mem[22]-=1; mem[35]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[22]+=1; } while(mem[29]){ mem[29]-=1; mem[35]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[29]+=1; } while(mem[6]){ mem[6]-=1; mem[35]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[6]+=1; } while(mem[7]){ mem[7]-=1; mem[36]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[7]+=1; } while(mem[20]){ mem[20]-=1; mem[36]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[20]+=1; } while(mem[3]){ mem[3]-=1; mem[36]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[3]+=1; } while(mem[17]){ mem[17]-=1; mem[36]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[17]+=1; } while(mem[30]){ mem[30]-=1; mem[36]+=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[30]+=1; } mem[37]=0; mem[37]+=53; mem[38]=0; mem[38]-=28; mem[39]=0; mem[39]+=5; mem[40]=0; mem[40]-=98; mem[41]=0; mem[41]+=73; mem[42]=0; mem[42]+=123; while(mem[31]){ mem[31]-=1; mem[37]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[31]+=1; } while(mem[32]){ mem[32]-=1; mem[38]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[32]+=1; } while(mem[33]){ mem[33]-=1; mem[39]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[33]+=1; } while(mem[34]){ mem[34]-=1; mem[40]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[34]+=1; } while(mem[35]){ mem[35]-=1; mem[41]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[35]+=1; } while(mem[36]){ mem[36]-=1; mem[42]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[36]+=1; } mem[43]=0; mem[43]+=48; while(mem[37]){ mem[43]+=1; mem[37]=0; } while(mem[38]){ mem[43]+=1; mem[38]=0; } while(mem[39]){ mem[43]+=1; mem[39]=0; } while(mem[40]){ mem[43]+=1; mem[40]=0; } while(mem[41]){ mem[43]+=1; mem[41]=0; } while(mem[42]){ mem[43]+=1; mem[42]=0; } scanf("%c",&mem[44]); scanf("%c",&mem[45]); scanf("%c",&mem[46]); scanf("%c",&mem[47]); scanf("%c",&mem[48]); scanf("%c",&mem[49]); mem[50]=0; mem[50]+=101; mem[51]=0; mem[51]+=95; mem[52]=0; mem[52]+=67; mem[53]=0; mem[53]+=48; mem[54]=0; mem[54]+=100; mem[55]=0; mem[55]+=51; while(mem[44]){ mem[44]-=1; mem[50]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[44]+=1; } while(mem[45]){ mem[45]-=1; mem[51]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[45]+=1; } while(mem[46]){ mem[46]-=1; mem[52]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[46]+=1; } while(mem[47]){ mem[47]-=1; mem[53]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[47]+=1; } while(mem[48]){ mem[48]-=1; mem[54]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[48]+=1; } while(mem[49]){ mem[49]-=1; mem[55]-=1; mem[0]+=1; } while(mem[0]){ mem[0]-=1; mem[49]+=1; } while(mem[50]){ mem[43]+=1; mem[50]=0; } while(mem[51]){ mem[43]+=1; mem[51]=0; } while(mem[52]){ mem[43]+=1; mem[52]=0; } while(mem[53]){ mem[43]+=1; mem[53]=0; } while(mem[54]){ mem[43]+=1; mem[54]=0; } while(mem[55]){ mem[43]+=1; mem[55]=0; } printf("%c",mem[43]); return 0;}

于是现在的任务就成了分两次输入6个字符,经过处理后若mem[43]==48(原二进制文件中的判断逻辑)就能得到flag。

这个C程序还是比较冗杂(毕竟九百多行),所以对其进行找规律分析化简。

先拿出前四个while即[line 10, line 27]进行分析:

while(mem[1]){    mem[1]-=1;    mem[7]+=1;    mem[0]+=1;} // mem[7]+=mem[1];mem[0]+=mem[1];mem[1]=0;while(mem[0]){    mem[0]-=1;    mem[1]+=1;} // mem[1]+=mem[0];mem[0]=0;while(mem[1]){    mem[1]-=1;    mem[7]+=1;    mem[0]+=1;} // mem[7]+=mem[1];mem[0]+=mem[1];mem[1]=0;while(mem[0]){    mem[0]-=1;    mem[1]+=1;} // mem[1]+=mem[0];mem[0]=0;

也就是说整段等同于:

mem[7]+=mem[1]*2;// mem[0]和mem[1]没变

所以接下来的(6-1)*4个循环也做相同处理,即[line 10, line 117]可以简化为:

mem[7]+=mem[1]*2;mem[8]+=mem[2]*2;mem[9]+=mem[3]*2;mem[10]+=mem[4]*2;mem[11]+=mem[5]*2;mem[12]+=mem[6]*2;

然后再拿出四个while即[line 118, line 135]进行分析:

while(mem[7]){    mem[7]-=1;    mem[13]+=1;    mem[0]+=1;} // mem[13]+=mem[7];mem[0]+=mem[7];mem[7]=0;while(mem[0]){    mem[0]-=1;    mem[7]+=1;} // mem[7]+=mem[0];mem[0]=0;while(mem[1]){    mem[1]-=1;    mem[13]+=1;    mem[0]+=1;} // mem[13]+=mem[1];mem[0]+=mem[1];mem[1]=0;while(mem[0]){    mem[0]-=1;    mem[1]+=1;} // mem[1]+=mem[0];mem[0]=0;

所以整段等同于:

mem[13]=mem[1]+mem[7];

所以[line 118, line 225]简化为:

mem[13]=mem[1]+mem[7];mem[14]=mem[2]+mem[8];mem[15]=mem[3]+mem[9];mem[16]=mem[4]+mem[10];mem[17]=mem[5]+mem[11];mem[18]=mem[6]+mem[12];

最后[line 10, line 803]可简化为

mem[7]+=mem[1]*2;mem[8]+=mem[2]*2;mem[9]+=mem[3]*2;mem[10]+=mem[4]*2;mem[11]+=mem[5]*2;mem[12]+=mem[6]*2;// [line 10, line 117]mem[13]=mem[1]+mem[7];mem[14]=mem[2]+mem[8];mem[15]=mem[3]+mem[9];mem[16]=mem[4]+mem[10];mem[17]=mem[5]+mem[11];mem[18]=mem[6]+mem[12];// [line 118, line 225]mem[19]=mem[1]+mem[13];mem[20]=mem[2]+mem[14];mem[21]=mem[3]+mem[15];mem[22]=mem[4]+mem[16];mem[23]=mem[5]+mem[17];mem[24]=mem[6]+mem[18];// [line 226, line 333]mem[25]=mem[1]+mem[19];mem[26]=mem[2]+mem[20];mem[27]=mem[3]+mem[21];mem[28]=mem[4]+mem[22];mem[29]=mem[5]+mem[23];mem[30]=mem[6]+mem[24];// [line 334, line 441]mem[31]=mem[2]+mem[9]+mem[16]+mem[23]+mem[30];mem[32]=mem[25]+mem[20]+mem[15]+mem[10]+mem[5];mem[33]=mem[13]+mem[8]+mem[3]+mem[22]+mem[30];mem[34]=mem[7]+mem[2]+mem[21]+mem[28]+mem[17];mem[35]=mem[8]+mem[15]+mem[22]+mem[29]+mem[6];mem[36]=mem[7]+mem[20]+mem[3]+mem[17]+mem[30];// [line 442, line 711]mem[37]=53;mem[38]=-28;mem[39]=5;mem[40]=-98;mem[41]=73;mem[42]=123;// [line 712, line 723]mem[37]-=mem[31];mem[38]-=mem[32];mem[39]-=mem[33];mem[40]-=mem[34];mem[41]-=mem[35];mem[42]-=mem[36];// [line 724, line 777]mem[43]=48;// [line 778, line 779]for(int i=37;i<=42;i++){    if(mem[i]) mem[43]+=1;    mem[i]=0;}// [line 780, line 803]

后半段输入后,处理的简化程序为:

mem[50]=101;mem[51]=95;mem[52]=67;mem[53]=48;mem[54]=100;mem[55]=51;// [line 810, line 821]mem[50]-=mem[44];mem[51]-=mem[45];mem[52]-=mem[46];mem[53]-=mem[47];mem[54]-=mem[48];mem[55]-=mem[49];// [line 822, line 875]for(int i=50;i<=55;i++){    if(mem[i]) mem[43]+=1;    mem[i]=0;}// [line 876, line 899]

至此分析完成。

而mem[43]一开始赋值就是48,也就是说两个for循环都不能进到if里。令s[12]为所求字符串,则可以得出方程组:

s[1]+s[2]*2+s[3]*3+s[4]*4+s[5]*5==53;//mem[2]+mem[9]+mem[16]+mem[23]+mem[30]==53;s[0]*5+s[1]*4+s[2]*3+s[3]*2+s[4]*1==-28;//mem[25]+mem[20]+mem[15]+mem[10]+mem[5]==-28;s[0]*3+s[1]*2+s[2]*1+s[3]*4+s[5]*5==5;//mem[13]+mem[8]+mem[3]+mem[22]+mem[30]==5;s[0]*2+s[1]*1+s[2]*4+s[3]*5+s[4]*3==-98;//mem[7]+mem[2]+mem[21]+mem[28]+mem[17]==-98;s[1]*2+s[2]*3+s[3]*4+s[4]*5+s[5]*1==73;//mem[8]+mem[15]+mem[22]+mem[29]+mem[6]==73;s[0]*2+s[1]*4+s[2]*1+s[4]*3+s[5]*5==123;//mem[7]+mem[20]+mem[3]+mem[17]+mem[30]==123;s[6]==101;s[7]==95;s[8]==67;s[9]==48;s[10]==100;s[11]==51;

因为涉及到char型数据解方程的问题,s[0]-s[5]不好直接出,爆破又太慢了,所以决定构造一个程序用angr破:

// useAngr.c#include 
int main(){ char s[6]={0}; scanf("%6s",s); char x1=s[1]+s[2]*2+s[3]*3+s[4]*4+s[5]*5; char x2=s[0]*5+s[1]*4+s[2]*3+s[3]*2+s[4]*1; char x3=s[0]*3+s[1]*2+s[2]*1+s[3]*4+s[5]*5; char x4=s[0]*2+s[1]*1+s[2]*4+s[3]*5+s[4]*3; char x5=s[1]*2+s[2]*3+s[3]*4+s[4]*5+s[5]*1; char x6=s[0]*2+s[1]*4+s[2]*1+s[4]*3+s[5]*5; if(x1==53&&x2==-28&&x3==5&&x4==-98&&x5==73&&x6==123) printf("Congratulations!!!!!!"); return 0;}

useAngr_exp:

import timeimport angrimport syst=time.clock()path_to_binary='./useAngr'project=angr.Project(path_to_binary,auto_load_libs=False)initial_state=project.factory.entry_state()simulation=project.factory.simgr(initial_state)find_address=0x4008CCsimulation.one_active.options.add(angr.options.LAZY_SOLVES)simulation.explore(find=find_address)print('time:',round(time.clock()-t,2),'s')if simulation.found:    solution_state=simulation.found[0]    print(solution_state.posix.dumps(sys.stdin.fileno()))else:    raise Exception('Could not find the solution. _0x0_')

解得:

有不可见字符,不过可以通过-0x80得到可见字符(估计是前面判定+和-的地方有点出入,问题不大)。

最后整理得到字符串:

key1=b'\xd23v\xe5\xd2\xd3'for c in key1:    if c>0x7f:        print(chr(c-0x80),end='')    else:        print(chr(c),end='')key2=[101,95,67,48,100,51]for x in key2:    print(chr(x),end='')

由于要连远程拿flag,所以复现的时候只有本地打通没有flag,打通撒花~

R3veRSe_C0d3


[12.27] HarmonyOS和HMS专场

难得有一场ak逆向了!(虽然有大佬带着

有三道题都是卡着四血交,实惨TAT

re123

用file命令可以看到是MS Windows HtmlHelp Data文件(即.chm),查看文件头也可以知道。

所以添加后缀名.chm。

关于chm文件有一个常用的反编译器ChmDecompiler,可以释放CHM里面的全部源文件(包括网页、文本、图片、CHM、ZIP、EXE等全部源文件),并且完美地恢复源文件的全部目录结构 (摘抄的简介

所以用ChmDecompiler打开re.chm,解压缩,可以看到目录下出现一个包含四个文件的文件夹(其实源文件只有三个,.hhp是ChmDecompiler自动生成的)。

一个一个翻可以看到doc.htm里有一段奇怪的Item1。

大概可以看到是powershell的语法?(感觉像win后门,这么多no的参数

查了一下其实就是把后面那大段进行base64解码而已,用wsl解一下base64有

然后得到了一段.NET代码(白字)。

通过查微软文档可以知道,这里是把base64解码以后的字符进行Deflate解压的过程,所以用脚本把中间那段base64解码,并整理输出。

import base64import zlib def deflate(data):    try:        return zlib.decompress(data, -zlib.MAX_WBITS)    except zlib.error:        return zlib.decompress(data)code='TY5BC4IwGIbvgv9hjB2McJhEhNChJMGTkN2qg7qvFHQT/bL575vpoV2/53n2skJJBInkQG5xwqOqhkcQXCATx7q+gkaHsvYj7kIVvCgburItVgm9MTxbVB5LATp5OlQvb6IMV0LdQvdPpu+8x66SL2eOrMl+Ck7naUA69ggND5UcoEOzI+pUc8p62G3TRZubv34K6IbLespADoGR27vv+R7HpqXzt8Q9y0IJI5N8RLCtLw=='de_code=deflate(base64.b64decode(code)).decode()for x in de_code.split('\r\n'):    print(x)

很明显的逻辑了,把doc.chm(应该是原来的re.chm)中"xxxxxxxx"后面的部分提取出来,还是用base64解码得到文件。

把这后面的内容手动复制出来到cont.txt里,进行base64解码,最后存在theFile中。

base64 -d cont.txt > theFile

查看theFile可以猜测是exe(毕竟最开始给的就是有powershell指令的base64),把文件头补上,并改后缀名(即theFile.exe)。

用ida打开,通过FindCrypt插件可以看到AES,跟过去能看到AES加密时的S盒(其实这里前两个都是S盒,第三个是逆S盒),猜测用到了AES加密。

往上回溯找到主函数

显然,这里是AES加密过程,sub_180001100()是密钥拓展过程,sub_1800015B0()是AES加密。

关于逆向中各种常见密码的记录,指路:

看了一下感觉是原装无魔改的AES,密文密钥都给了,那就直接写脚本解密。

注意这里是以整数形式给出的,别忘了小端序。

from Crypto.Cipher import AESfrom binascii import *arr=[0x16157E2B,0xA6D2AE28,0x8815F7AB,0x3C4FCF09]key=""for i in range(4):    key=hex(arr[i])[2:]+keykey=unhexlify(key)[::-1] #注意小端序的问题tmp=0x46C42084AA2A1B56E799D643453FF4B5cipher=unhexlify(hex(tmp)[2:])[::-1]enc=AES.new(key,AES.MODE_ECB)print(enc.decrypt(cipher))

flag{youcangues}

puzzle

mips架构。

加载进ida以后,通过字符串回溯找到主函数。

可以看到很明显的sub_401134()这个check,先往这里面看。

看到是一个疑似maze的逻辑(

不过sub_400FA8()点进去以后可以看到是swap的功能

所以应该不是maze,是一个以交换为主的逻辑。

至于dword_4A0010,可以看到是一个九个数的数组。

v4和v5的出处在switch逻辑上面一点

可以看到最后(v4,v5)其实表示了数组里0的位置,且数组实际可以看成是3*3。

即:

4 0 37 2 68 1 5

最后sub_400FFC()的检查逻辑:

实际上就是要让这个3*3等于

1 2 34 5 67 8 0

把0看成空位的话,很容易就想到3*3的华容道了。

(或者玩算法的小伙伴可能对八数码问题这个名字更熟悉?

有本事下次出数织啊!20*20我都给你火速解出来(来自数织爱好者的吐槽)

这里实际上是求最短能得到的路径(15步),懒得想了,直接去网上抓了个现成代码下来改了改。

八数码问题的代码见:

#include 
#include
#include
#include
#define maxState 10000#define N 3using namespace std;bool isEqual(int a[N][N][maxState],int b[N][N],int n){ for(int i = 0;i < N;i ++){ for(int j = 0;j < N;j ++){ if(a[i][j][n] != b[i][j]) return false; } } return true;}bool isEqual(int a[N][N],int b[N][N]){ for(int i = 0;i < N;i ++){ for(int j = 0;j < N;j ++){ if(a[i][j] != b[i][j]) return false; } } return true;}int evalute(int state[N][N],int target[N][N]){ int num = 0; for(int i = 0;i < N;i ++){ for(int j = 0;j < N;j ++) if(state[i][j] != target[i][j]) num ++; } return num;}void findBrack(int a[N][N],int x,int y){ for(int i = 0;i < N;i ++){ for(int j = 0;j < N;j ++){ if(a[i][j] == 0) { x = i;y = j;return; } } }}bool move(int a[N][N],int b[N][N],int dir){ //1 up 2 down 3 left 4 right int x = 0,y = 0; for(int i = 0;i < N;i ++){ for(int j = 0;j < N;j ++){ b[i][j] = a[i][j]; if(a[i][j] == 0) { x = i;y = j; } } } if(x == 0 && dir == 1) return false; if(x == N-1 && dir == 2) return false; if(y == 0 && dir == 3) return false; if(y == N-1 && dir == 4) return false; if(dir == 1){b[x-1][y] = 0;b[x][y] = a[x-1][y];} else if(dir == 2){b[x+1][y] = 0;b[x][y] = a[x+1][y];} else if(dir == 3){b[x][y-1] = 0;b[x][y] = a[x][y-1];} else if(dir == 4){b[x][y+1] = 0;b[x][y] = a[x][y+1];} else return false; return true;}void statecpy(int a[N][N][maxState],int b[N][N],int n){ for(int i = 0;i < N;i ++){ for(int j = 0;j < N;j ++){ a[i][j][n] = b[i][j]; } }}void getState(int a[N][N][maxState],int b[N][N],int n){ for(int i = 0;i < N;i ++){ for(int j = 0;j < N;j ++){ b[i][j] = a[i][j][n]; } }}void statecpy(int a[N][N],int b[N][N]){ for(int i = 0;i < N;i++){ for(int j = 0;j < N;j++) a[i][j] = b[i][j]; }}int checkAdd(int a[N][N][maxState],int b[N][N],int n){ for(int i = 0;i < n;i ++){ if(isEqual(a,b,i)) return i; } return -1;}int Astar(int a[N][N][maxState],int start[N][N],int target[N][N],int path[maxState]){ bool visited[maxState] = {false}; int fitness[maxState] = {0}; int passLen[maxState] = {0}; int curpos[N][N]; statecpy(curpos,start); int id = 0,Curid = 0; fitness[id] = evalute(curpos,target); statecpy(a,start,id++); while(!isEqual(curpos,target)){ for(int i = 1;i < 5;i ++){//向四周找方向 int tmp[N][N] = {0}; if(move(curpos,tmp,i)){ int state = checkAdd(a,tmp,id); if(state == -1){//not add path[id] = Curid; passLen[id] = passLen[Curid] + 1; fitness[id] = evalute(tmp,target) + passLen[id]; statecpy(a,tmp,id++); }else{//add int len = passLen[Curid] + 1,fit = evalute(tmp,target) + len; if(fit < fitness[state]){ path[state] = Curid; passLen[state] = len; fitness[state] = fit; visited[state] = false; } } } } visited[Curid] = true; //找到适应度最小的最为下一个带搜索节点 int minCur = -1; for(int i = 0;i < id;i ++) if(!visited[i] && (minCur == -1 || fitness[i] < fitness[minCur])) minCur = i; Curid = minCur; getState(a,curpos,Curid); if(id == maxState) return -1; } return Curid;}void show(int a[N][N][maxState],int n){ cout << "-------------------------------\n"; for(int i = 0;i < N;i ++){ for(int j =0;j < N;j ++){ cout << a[i][j][n] << " "; } cout << endl; } cout << "-------------------------------\n";}int calDe(int a[N][N]){ int sum = 0; for(int i = 0;i < N*N;i ++){ for(int j = i+1;j < N*N;j ++){ int m,n,c,d; m = i/N;n = i%N; c = j/N;d = j%N; if(a[c][d] == 0) continue; if(a[m][n] > a[c][d]) sum ++; } } return sum;}void autoGenerate(int a[N][N]){ int maxMove = 50; srand((unsigned)time(NULL)); int tmp[N][N]; while(maxMove --){ int dir = rand()%4 + 1; if(move(a,tmp,dir)) statecpy(a,tmp); }}int main(){ int a[N][N][maxState] = {0}; // int start[N][N] = {1,2,3,4,5,6,7,8,0}; // autoGenerate(start); // cout << start[0][0] << start[1][1]; int start[N][N] = {4,0,3,7,2,6,8,1,5}; int target[N][N] = {1,2,3,4,5,6,7,8,0}; if(!(calDe(start)%2 == calDe(target)%2)){ cout << "无解\n"; return 0; } int path[maxState] = {0}; int res = Astar(a,start,target,path); if(res == -1){ cout << "达到最大搜索能力\n"; return 0; } int shortest[maxState] = {0},j = 0; while(res != 0){ shortest[j++] = res; res = path[res]; } cout << "第 0 步\n"; show(a,0); for(int i = j - 1;i >= 0;i --){ cout << "第 " << j-i << " 步\n"; show(a,shortest[i]); } return 0;}

得到每一步的情况,进而根据switch写出路径。

第 0 步-------------------------------4 0 37 2 68 1 5-------------------------------第 1 步-------------------------------4 2 37 0 68 1 5-------------------------------第 2 步-------------------------------4 2 37 1 68 0 5-------------------------------第 3 步-------------------------------4 2 37 1 68 5 0-------------------------------第 4 步-------------------------------4 2 37 1 08 5 6-------------------------------第 5 步-------------------------------4 2 07 1 38 5 6-------------------------------第 6 步-------------------------------4 0 27 1 38 5 6-------------------------------第 7 步-------------------------------4 1 27 0 38 5 6-------------------------------第 8 步-------------------------------4 1 27 5 38 0 6-------------------------------第 9 步-------------------------------4 1 27 5 30 8 6-------------------------------第 10 步-------------------------------4 1 20 5 37 8 6-------------------------------第 11 步-------------------------------0 1 24 5 37 8 6-------------------------------第 12 步-------------------------------1 0 24 5 37 8 6-------------------------------第 13 步-------------------------------1 2 04 5 37 8 6-------------------------------第 14 步-------------------------------1 2 34 5 07 8 6-------------------------------第 15 步-------------------------------1 2 34 5 67 8 0-------------------------------6 左2 上4 右8 下// 884226886224488

路径为“884226886224488”。

接下来看主函数里check上面的部分,看到sub_409070()实际上是一个scanf,而dword_4A1B60是我们的输入,也就是最后的flag,中间对输入进行处理以后才得到“884226886224488”这个字符串。

在里面翻可以翻到一个sub_400B58(),猜测是base64换表编码。

于是尝试写脚本编码。

import base64b64table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"mytable=""offset=-18for i in range(len(b64table)):    mytable+=b64table[(i+offset)%len(b64table)]text="884226886224488".encode()cipher=base64.b64encode(text).decode().translate(str.maketrans(b64table,mytable))print(cipher)

试试能不能过check。

wsl运行:(要装qemu才能执行,毕竟特殊架构。

cp $(which qemu-mips) ../qemu-mips -L . ./puzzle

执行mips程序,输入脚本中解出的字符串,发现成功了,get flag。

flag{8xOi6R2k8xOk6R2i7xOm}

aRm

arm架构。

照例通过字符串回溯找到主函数。

v1是key,v9是输入的flag,对输入的限制就是长度为42且头尾是“flag{”和“}”。

动态调一下可以发现,sub_27770()这个函数实际上是把unk_723A0数组里的42个数据复制到v8里。

./qemu-arm -L ./ -g 12345 ./aRm

(Debugger选Remote GDB debugger,把端口号填上就好,其余配置具体见中调试elf部分。

现在我们未知的数就剩v5和v6了,v5要看sub_1714C()的输出,v6这里相当于是42条42元一次方程组(输入未知的情况下)。

而sub_105B4()是输出42个结果,于是可以知道只要输出了output.txt里的42个数就是正确的flag了。

由于前面有一个sub_169AC(key),这边又是一个无参的sub_1714C()+1,于是猜测是srand(seed)和rand()。

为了证明猜测,多次运行程序输入同一个key和相同/不同的flag,发现每一次的v5是一样的,结合rand()的伪随机性,确定这就是随机函数。

由于key只有一字节(0~255),干脆直接爆破。把output.txt的数据读入,用sympy库解方程,只要第一个解x0等于ord('f')^v8[0]=102^0xA0=198,就说明这个key有极大可能性是正确的key。

当然,在此之前,我们得先知道每一次的v5(即方程的系数)是多少。

于是hook函数,在v5生成之后复用程序原来就有的print函数及格式符,把每次生成的v5都打印出来。

还记得有个函数是可以输出八位十六进制数的吧,就是那个sub_105B4(),我们可以用这里面的printf,然后把调用这个函数的地方nop掉(目标要明确,现在是为了爆破key,没必要管程序的正常性hahah)。

本来是想自己堆个调用printf出来的,不知道为什么keypatch对LDR R0, =a08x解释不了,于是只好绕个小路了。

转到汇编窗口,记一下这里的loc,等会要跳过来的。

看回去原来二重循环里出v5那个地方

这几条语句的意思就是f5里面的那行v5 = (unsigned __int8)(sub_1714C() + 1);,我们从再下一行开始改。

注意可以改的范围在蓝框这里,这是我们不需要的v6[j] += (unsigned __int8)v9[k] * v5;,在这个范围里可以尽情修改,剩下的nop掉。

用keypatch直接输入汇编,patch后面的语句为

(其实就是改了一行B loc_105D4,剩下的直接Fill with NOPs就好)

接下来去往loc_105D4,改造一下。

我们知道,现在R3寄存器里实际上存的是v5的值,我们调用printf直接输出R3的值就能达成目标。

在ARM汇编里,函数传参用R0、R1……所以我们这里给R1一个R3的值就好。

这里本来就是MOV R1, R3不用改,所以直接把前面nop掉。

因为v5那里是取(unsigned __int8),所以把这里改一下,把"%08x"改成"%02x",就是出来的v5。

别忘了后面还要跳回去,找到地址:

patch:

记得把调用sub_105B4()的地方也nop掉。

最后把patch的字节保存一下。

运行测试一下,有:

ok,hook成功,开始爆破。

用pexpect进行批量的自动化交互见:

多亏了周五做的那个题,才有了这个题的爆破脚本(Doge。

import pexpectfrom sympy import *data=[]with open('output.txt','r') as f:    tmp=f.read().split('\r\n')    data=[int(x,16) for x in tmp]src=[0xA0, 0xE4, 0xBA, 0xFB, 0x10, 0xDD, 0xAC, 0x65, 0x8D, 0x0B, 0x57, 0x1A, 0xE4, 0x28, 0x96, 0xB3, 0x0C, 0x79, 0x4D, 0x80, 0x90, 0x99, 0x58, 0xFE, 0x50, 0xD3, 0xF9, 0x3C, 0x0F, 0xC1, 0xE3, 0xA6, 0x39, 0xC3, 0x28, 0x75, 0xF8, 0xC9, 0xC8, 0xCD, 0x78, 0x26]flag='flag{000000000000000000000000000000000000}'var=[]for num in range(42):    exec("x"+str(num)+"=Symbol('x'+str(num))")    var.append("x"+str(num)) #创建42个变量x0~x41for i in range(256):    r=pexpect.spawn('./qemu-arm -L ./ ./aRm_getRand')    r.sendline(str(i))    r.sendline(flag)    r.readline()    r.readline()    rand=[]    for j in range(42*42):        s=r.readline()        rand.append(int(str(s)[2:-5],16))    r.wait()    exper=[]    for j in range(42):        anEx=""        for k in range(42):            anEx+=str(rand[j*42+k])+"*"+var[k]+"+"        anEx=anEx[:-1]+"-"+str(data[j])        exper.append(anEx)    res=solve(exper,var)    print(str(i)+": ")    print(res.values())

爆破得到:

可知key是82,而v9在xor以后的数组也爆出来了,简单xor得flag:

arr=[0xA0, 0xE4, 0xBA, 0xFB, 0x10, 0xDD, 0xAC, 0x65, 0x8D, 0x0B, 0x57, 0x1A, 0xE4, 0x28, 0x96, 0xB3, 0x0C, 0x79, 0x4D, 0x80, 0x90, 0x99, 0x58, 0xFE, 0x50, 0xD3, 0xF9, 0x3C, 0x0F, 0xC1, 0xE3, 0xA6, 0x39, 0xC3, 0x28, 0x75, 0xF8, 0xC9, 0xC8, 0xCD, 0x78, 0x26]x=[198, 136, 219, 156, 107, 228, 152, 7, 239, 63, 97, 127, 134, 5, 247, 131, 109, 75, 96, 180, 241, 173, 57, 211, 49, 224, 157, 9, 34, 243, 129, 199, 1, 244, 31, 17, 157, 171, 252, 249, 64, 91]flag=""for i in range(42):    flag+=chr(x[i]^arr[i])print(flag)

flag{94bb46eb-a0a2-4a4a-a3d5-2ba877deb448}

pe

arm架构,没环境调不动,只能硬看了XD。这题有好多奇怪的函数,而且通过伪代码跟的话就能看到函数套函数套函数……所以基本靠猜出来的(

继续通过字符串回溯找主函数。

根据参数猜测,sub_1400023C8()是strcmp()的作用,我们需要让v9="KIMLXDWRZXTHXTHQTXTXHZWC"。

再往上走,sub_1400015B0这个函数调用了v9,于是跟进去看功能。

感觉是某种加密,以相邻的两字符为一组,对这两个字符做相同的操作,再做后续处理。

跟进sub_1400012B8()里看,可以看到大概是一个搜索的过程

如果不等于-1就说明在表中找到了这个元素,然后返回一个索引(?

再往下看好像就看不太懂了,然后就是玄学的猜猜猜= =

回去看string可以看到一个这个,猜测是密钥表之类的?

往上回溯也看不到什么线索,不过可以发现这25个数字刚好没有相同的。

现在总结一下这个古典加密算法的特点,大概是两个为一组处理+已定义的密钥表(即不是通过输入生成的)5*5+处理时用到索引。

很久很久以前想写某对cp的AU同人时想把ctf元素混进去,就看了很多简单又奇奇怪怪的编码/古典密码(现代密码太学术了XD),没想到现在有用武之地了(手动狗头。

安利一个编码/古典密码的集合:

然后翻到了一个符合这个特点的密码,Playfair Cipher:

不同的是密码表是直接给出的,不过加密流程再对回ida里的反编译感觉挺像的,于是果断试试。

按照Playfair Cipher的加解密流程写出脚本:

def getIndex(c):    for i in range(len(key)):        if key[i].find(c)!=-1:            return i,key[i].find(c)letter_list="ABCDEFGHJKLMNOPQRSTUVWXYZ"key=["CREIH","TQGNU","AOVXL","DZKYM","PBWFS"]cipher="KIMLXDWRZXTHXTHQTXTXHZWC"text=""for i in range(0,len(cipher),2):    j=i+1    x1,y1=getIndex(cipher[i])    x2,y2=getIndex(cipher[j])    if x1==x2:        text+=key[x1][(y1+1)%5]+key[x2][(y2+1)%5]    elif y1==y2:        text+=key[(x1+1)%5][y1]+key[(x2+1)%5][y2]    else:        text+=key[x1][y2]+key[x2][y1]print(text)

走一遍脚本解密可以得到:

YES MAYBE YOU CAN RUN AN ARM PE

No, I can't 😦

看起来能读的通,成功get flag。

flag{YESMAYBEYOUCANRUNANARMPE}

crash

用binwalk分析给的crash文件

可以看到0x1000处有一个 ELF, 32-bit LSB executable,先把这个可执行文件用dd分离出来。

其中if=输入文件名(被分离的),of=输出文件名(分离出来的),skip=跳过的块(bs指定字节)数,count=块长度,最后得到file_0x1000文件。

用ida打开如果出现这个warning,可以用 的方法解决。

老样子,通过shift+F12寻找字符串,通过交叉引用找到主函数。

先通过一些参数和常用逻辑的猜测给系统函数命名,方便后续分析。

然后就剩sub_8048737()sub_80487E7这两个加密函数了。

第一个就很简单啦,简单xor。

第二个点进sub_80489E9()可以看到md5经典常数,说明这一系列大概是个md5加密(当然md5的实现还是要看看的。

退回去,看到0x804B060这里,很像数组的始地址。

于是转到IDA View,按G跳到这个地址,可以看到一堆可见字符,按A转成字符串。

再对回去逻辑就很明显了,就是依次取四个字符进行md5加密,然后跟这八个字符串比。

于是exp就可以写啦,爆破md5:

# python2from hashlib import md5dst=['bf2b36d56f5757c13cad80494b385e78','3fe9dbae5dc4408350500affa20074aa','1fa6770eca6b57e47a042ffe52eca8ff','1aad6b7da1122b4b5a53bf5a4d3b11b0','e7b77d9e0ab19fc9ea98154f994fccc5','75d9128cfeb61b8949664f6a067f6469','d8b0a52c64d6075017b7346140550c46','306529c7cdedfb06e27b39f7b2babf4d']res=[]for a in range(33,127):    for b in range(33,127):        for c in range(33,127):            for d in range(33,127):                l=[a^0x17,b^0x17,c^0x17,d^0x17]                tmp=''.join(list(map(chr,l)))                tmpmd5=md5(tmp).hexdigest()                if tmpmd5 in dst:                    s=''.join(list(map(chr,[a,b,c,d])))                    res.append((dst.index(tmpmd5),s))                    if len(res)==8:                        break            else:                continue            break        else:            continue        break    else:        continue    breakres.sort(key=(lambda x:x[0]))flag=''.join([x[1] for x in res])print(flag)

得到flag:

flag{ux1cy1x4iltkahbc9nu1nk00d9akpp7w}

上一篇:【wp】HWS计划2021硬件安全冬令营线上选拔赛
下一篇:【wp】2020ChaMd5圣诞题

发表评论

最新留言

感谢大佬
[***.8.128.20]2025年05月03日 03时09分03秒