暑假第二周

Rev_Dizzy

xuenixiang.com上的一道题
F5 反编译失败提示
img
这里可以展开查看汇编代码
img
一种方法是直接手撸汇编代码,因为汇编代码中只有add,sub,xor三种操作,
可以尝试手撸汇编,或者交给Chat_GPT
搜索一番后学到还有一种解决方法
可以通过修改IDA配置文件\cfg\hexrays.cfg
将里面的MAX_FUNCSIZE改大一点例如1024
可以看到注释里面也说明了若函数大于64K的话会无法反汇编,所以我们将它改大
img
反汇编后逻辑很简单就是5000多行的加减异或操作后与密文比较
img
只需要将加替换成减,减替换成加然后倒着跑一遍密文就行
将加密的5000多行复制下来保存为data.txt
注意跑的时候要& 0xff防止溢出
用exec函数执行字符串代码

exp

with open('data.txt', 'rb') as fp:
    data = fp.read()
flag = [0x27,0x3C,0xE3,0xFC,0x2E,0x41,0x07,0x5E,0x62,0xCF,
        0xE8,0xF2,0x92,0x80,0xE2,0x36,0xB4,0xB2,0x67,0x77,
        0x0F,0xF6,0x0D,0xB6,0xED,0x1C,0x65,0x8A,0x07,0x53,
        0xA6,0x66]
fp1 = open("ans.txt", "w")
data = data.split(b'\n')
for i in data[::-1]:
    tmp = i[2:].decode()
    if '+' in tmp:
        tmp = tmp.replace('+', '-')
        code = tmp + '\n' + tmp[:tmp.find('-')] + "&= 0xff"
    elif '-' in tmp:
        tmp = tmp.replace('-', '+')
        code = tmp + '\n' + tmp[:tmp.find('+')] + "&= 0xff"
    else: code = tmp + '\n' + tmp[:tmp.find('^')] + "&= 0xff"
    fp1.write(tmp+'\n')
    exec(code)
fp1.close()
fp.close()
for i in flag:
  print(chr(i),end='')

flag

flag{Try_R3vers1ng_W1th_ScR!pt!}

[CatCTF]The cat did it

点进来很复杂一个函数图像,猫猫可爱捏
flag是CatCTF{MD5(我离开猫猫的概率)}
img
我的定义域是[-200,200]拖动一下我
可以发现无论怎么拖都有一部分是在猫猫体内的
所以猜测概率为0%,算一下md5
img

flag

CatCTF{9f1ef07877f9d85a82bd500f408b4814}

[BUUCTF]rsa

RSA介绍

RSA 加密算法是一种非对称加密算法。在公开密钥加密和电子商业中 RSA 被广泛使用。RSA 是 1977 年由罗纳德 · 李维斯特(Ron Rivest)、阿迪 · 萨莫尔(Adi Shamir)和伦纳德 · 阿德曼(Leonard Adleman)一起提出的。RSA 就是他们三人姓氏开头字母拼在一起组成的。
RSA 算法的可靠性由极大整数因数分解的难度决定。换言之,对一极大整数做因数分解愈困难,RSA 算法愈可靠。假如有人找到一种快速因数分解的算法的话,那么用 RSA 加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。如今,只有短的 RSA 密钥才可能被强力方式解破。到 2017 年为止,还没有任何可靠的攻击 RSA 算法的方式。

原理

公钥与私钥的生成

  • 随机选择两个不同的大质数 \(p\)\(q\) 计算\(N = p \times q\)
  • 由欧拉函数\(\varphi(N)=\varphi(p)\varphi(q)=(p-1)(q-1)\)
  • 选择一个小于\(\varphi(N)\)的整数\(e\),使得\(e\)\(\varphi(N)\)互质
  • \(e\)关于\(\varphi(N)\)的乘法逆元\(d\),即求满足\(ed=1(\text{mod}\enspace \varphi(N))\)
  • \(p\)\(q\)的记录销毁
  • \((N,e)\)即为公钥,\((N,d)\)即为私钥

加密

首先需要将消息 以一个双方约定好的格式转化为一个小于\(N\),且与\(N\)互质的整数\(m\)。如果消息太长,可以将消息分为几段,这也就是我们所说的块加密,后对于每一部分利用如下公式加密:

\[m^{e}\equiv c(\text{mod}\enspace N) \]

解密

用d可以解密

\[c^{d}\equiv m(\text{mod}\enspace N) \]

解题过程

公钥解析

法一

在线公钥解析
img
在线分解质因数
img

法二

from Crypto.Util.number import *
from Crypto.PublicKey import RSA
import gmpy2
import rsa
from factordb.factordb import FactorDB

with open('pub.key','r') as f:
    key = RSA.import_key(f.read())
e = key.e
n = key.n
print('e = %d\nn = %d'%(e,n))
a = FactorDB(n)
a.connect()
fac = a.get_factor_list()
#或者factors = list(primefac.primefac(n))但是对大整数来说这个方法很慢
p,q = fac[0],fac[1]
print('p = %d\nn = %d'%(p,q))

解密

phi_n = (p-1)*(q-1)
d = gmpy2.invert(e, phi_n)
key = rsa.PrivateKey(p*q, e, d, p, q)

with open("flag.enc", 'rb') as file: 
    file = file.read()
    print(rsa.decrypt(file, key))  
#e = 65537
#n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
#p = 285960468890451637935629440372639283459
#q = 304008741604601924494328155975272418463
#b'flag{decrypt_256}\n'

完整exp

from Crypto.Util.number import *
from Crypto.PublicKey import RSA
import gmpy2
import rsa
from factordb.factordb import FactorDB

with open('pub.key','r') as f:
    key = RSA.import_key(f.read())
e = key.e
n = key.n
print('e = %d\nn = %d'%(e,n))
a = FactorDB(n)
a.connect()
fac = a.get_factor_list()
p,q = fac[0],fac[1]
print('p = %d\nn = %d'%(p,q))
phi_n = (p-1)*(q-1)
d = gmpy2.invert(e, phi_n)
key = rsa.PrivateKey(p*q, e, d, p, q)

with open("flag.enc", 'rb') as file: 
    file = file.read()
    print(rsa.decrypt(file, key))  
#e = 65537
#n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
#p = 285960468890451637935629440372639283459
#q = 304008741604601924494328155975272418463
#b'flag{decrypt_256}\n'

flag

flag{decrypt_256}

[FlareOn4]login

给出一个网页,F12查看源码

<!DOCTYPE Html />
<html>
    <head>
        <title>FLARE On 2017</title>
    </head>
    <body>
        <input type="text" name="flag" id="flag" value="Enter the flag" />
        <input type="button" id="prompt" value="Click to check the flag" />
        <script type="text/javascript">
            document.getElementById("prompt").onclick = function () {
                var flag = document.getElementById("flag").value;
                var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
                if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
                    alert("Correct flag!");
                } else {
                    alert("Incorrect flag, rot again");
                }
            }
        </script>
    </body>
</html>

ROT13加密,直接梭
img

flag

flag{ClientSideLoginsAreEasy@flare-on.com}

[SUCTF2019]SignIn

无壳直接查看主函数
gmpz函数不知道什么意思没关系,搜索学习一下
是GNU多精度算术库里的函数,GNU是一个提供了很多操作高精度的大整数,浮点数的运算的算术库,函数具体作用写在注释里了
img
这又是大整数又是取模,直接盲猜RSA
先用yafu先分解v4不要问我为什么不用factordb,就是叛逆喜欢瞎搞学各种方法
img

exp

import gmpy2
from Crypto.Util.number import *
import rsa
import binascii
e = 65537
p = 282164587459512124844245113950593348271
q = 366669102002966856876605669837014229419
n = 103461035900816914121390101299049044413950405173712170434161686539878160984549
phi_n = (p-1)*(q-1)
d = gmpy2.invert(e,phi_n)
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
m = gmpy2.powmod(c, d, n)
print(binascii.a2b_hex(hex(m)[2:].encode()))
#b'suctf{Pwn_@_hundred_years}'

flag

flag{Pwn_@_hundred_years}

[HDCTF2019]maze

查壳有UPX壳,先脱壳
img
尝试F5反汇编失败,阅读一下汇编代码
发现有一个jnz跳转到了未知地址
应该是个花指令,nop一下
img
img
nop完apply一下,重新打开就可以F5了
或者nop完全选红色地址,按一下P键快速patch
img
看到是一个简单的走迷宫函数,终点(5,-4)
img
在data段看到起点在(7,0),并且有迷宫地图,共70个字符,应该是7*10的迷宫
img

*******+**
******* **
****    **
**   *****
** **F****
**    ****
**********
#ssaaasaassdddw

手动走一下得到flag
img

flag

flag{ssaaasaassdddw}

[津门杯2021]GoodRe

把tea的运算操作都以函数形式呈现,耐心分析每个函数作用
然后重命名简化反汇编结果,以便分析
img
这是sub_1B30函数内部,通过分析各个函数可推断出是tea
img

exp

def tea_decrypt(data,key):
  i = 0
  delta = 0x830A5376 ^ 0x1D3D2ACF
  sum = delta * 32 & 0xffffffff
  while i < 32:
      i += 1
      data[1] -= ((data[0]<<4) + key[2]) ^ (data[0] + sum) ^ ((data[0]>>5) + key[3]) 
      data[1] = data[1] & 0xffffffff
      data[0] -= ((data[1]<<4) + key[0]) ^ (data[1] + sum) ^ ((data[1]>>5) + key[1]) 
      data[0] = data[0] & 0xffffffff
      sum -= delta
  return data
code =[0x79AE1A3B, 0x596080D3, 0x80E03E80, 0x846C8D73, 
       0x21A01CF7,0xC7CACA32, 0x45F9AC14, 0xC5F5F22F]
key = [17,17,17,17]
flag = ''
for j in range(0,8,2):
  endata = code[j:j+2] 
  dedata = tea_decrypt(endata,key)
  flag += hex(dedata[0])[2:]
  flag += hex(dedata[1])[2:]
print(flag.upper())
#7DEA3F6D3B3D6C0C620864ADD2FA2AE1A61F2736F0060DA0B97E8356D017CE59

flag

flag{7DEA3F6D3B3D6C0C620864ADD2FA2AE1A61F2736F0060DA0B97E8356D017CE59}

[ISCC]answer_to_everything

题目描述:
sha1 得到了一个神秘的二进制文件。寻找文件中的flag,解锁宇宙的秘密。注意:将得到的flag变为flag{XXX}形式提交。
直接定位到关键函数
img
flag应该就是kdudpeh,怎么提交都不对
回头看了一下题目描述,试一下sha1
img
对了,提醒我自己注意看题目描述

flag

flag{80ee2a3fe31da904c596d993f7f1de4827c1450a}

[RCTF2019]babyre1

提示:MD5(rctf{your answer}) == 5f8243a662cf71bf31d2b2602638dc1d
先看主函数,不是很复杂
img
输入正确flag会得到Bingo!,flag长度为16位
接下来重点就是sub_C00和sub_1180以及sub_13D0
首先sub_C00,理解一下就是把输入转换成16进制,理解不了可以动调验证
img
在sub_1180函数中调用了sub_CE0,可以根据特征判断是xxtea,
findcrypt插件也识别出了特征值,unk_202010是key
img
img
img
在xxtea加密后读取了结果最后一位,判断是否小于等于4,并根据数值进行操作
例如最后一位为3,则加密后的第6个字节为0,
最后一位为2,则加密后的第7个字节为0.
最后是sub_13D0函数,看不懂,根据特征^0x1021搜索了一下是CRC16校验
img
检验的是之前被赋值为0的数据之前的数据,则之前赋值为0相当于对数据进行了截断。
CRC16检验后再根据截断位置循环异或0x17
因为最后的输出是bingo!,长度为6,所以截断的位置是7,所以最后一位应该是02
bingo!与0x17异或得到55 7e 79 70 78 36,所以xxtea加密结果应该是
55 7e 79 70 78 36 xx 02第七位未知,但是可以通过爆破来得到
根据题目提示提示:MD5(rctf{your answer}) == 5f8243a662cf71bf31d2b2602638dc1d来检验
或者使用patch文件将加密改成解密后用pwntool的dump功能将255个结果写入文件
详细看这篇博客

exp

import xxtea
import hashlib
key = [0xc7,0xe0,0xc7,0xe0,0xd7,0xd3,0xf1,0xc6,0xd3,0xc6,0xd3,0xc6,0xce,0xd2,0xd0,0xc4]
text = [0x55,0x7e,0x79,0x70,0x78,0x36,0x0,0x02]
for i in range(0xff):
  text[6] = i
  encrypt_data = xxtea.encrypt(bytes(text),bytes(key),padding=False)
  encrypt_data = encrypt_data.hex()
  flag = "rctf{"+ encrypt_data +"}"
  if hashlib.md5(flag.encode()).digest().hex() == '5f8243a662cf71bf31d2b2602638dc1d':
    print(flag)
#rctf{05e8a376e4e0446e}

flag

flag{05e8a376e4e0446e}

[HITCON]handcrafted-pyc

这篇博客超详细
首先打开文件是一个python源码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import marshal, zlib, base64
exec(marshal.loads(zlib.decompress(base64.b64decode('eJyNVktv00AQXm/eL0igiaFA01IO4cIVCUGFBBJwqRAckLhEIQmtRfPwI0QIeio/hRO/hJ/CiStH2M/prj07diGRP43Hs9+MZ2fWMxbnP6mux+oK9xVMHPFViLdCTB0xkeKDFEFfTIU4E8KZq8dCvB4UlN3hGEsdddXU9QTLv1eFiGKGM4cKUgsFCNLFH7dFrS9poayFYmIZm1b0gyqxMOwJaU3r6xs9sW1ooakXuRv+un7Q0sIlLVzOCZq/XtsK2oTSYaZlStogXi1HV0iazoN2CV2HZeXqRQ54TlJRb7FUlKyUatISsdzo+P7UU1Gb1POdMruckepGwk9tIXQTftz2yBaT5JQovWvpSa6poJPuqgao+b9l5Aj/R+mLQIP4f6Q8Vb3g/5TB/TJxWGdZr9EQrmn99fwKtTvAZGU7wzS7GNpZpDm2JgCrr8wrmPoo54UqGampFIeS9ojXjc4E2yI06bq/4DRoUAc0nVnng4k6p7Ks0+j/S8z9V+NZ5dhmrJUM/y7JTJeRtnJ2TSYJvsFq3CQt/vnfqmQXt5KlpuRcIvDAmhnn2E0t9BJ3SvB/SfLWhuOWNiNVZ+h28g4wlwUp00w95si43rZ3r6+fUIEdgOZbQAsyFRRvBR6dla8KCzRdslar7WS+a5HFb39peIAmG7uZTHVm17Czxju4m6bayz8e7J40DzqM0jr0bmv9PmPvk6y5z57HU8wdTDHeiUJvBMAM4+0CpoAZ4BPgJeAYEAHmgAUgAHiAj4AVAGORtwd4AVgC3gEmgBBwCPgMWANOAQ8AbwBHgHuAp4D3gLuARwoGmNUizF/j4yDC5BWM1kNvvlxFA8xikRrBxHIUhutFMBlgQoshhPphGAXe/OggKqqb2cibxwuEXjUcQjccxi5eFRL1fDSbKrUhy2CMb2aLyepkegDWsBwPlrVC0/kLHmeCBQ=='))))

先将数据base64解密然后用zlib.decompress将解密后的字符串解压
接着用marshal.load将二进制数据反序列化为Python对象,最后exec执行代码
第一步先获取要执行的python代码

import zlib,base64
pyc=zlib.decompress(base64.b64decode('eJyNVktv00AQXm/eL0igiaFA01IO4cIVCUGFBBJwqRAckLhEIQmtRfPwI0QIeio/hRO/hJ/CiStH2M/prj07diGRP43Hs9+MZ2fWMxbnP6mux+oK9xVMHPFViLdCTB0xkeKDFEFfTIU4E8KZq8dCvB4UlN3hGEsdddXU9QTLv1eFiGKGM4cKUgsFCNLFH7dFrS9poayFYmIZm1b0gyqxMOwJaU3r6xs9sW1ooakXuRv+un7Q0sIlLVzOCZq/XtsK2oTSYaZlStogXi1HV0iazoN2CV2HZeXqRQ54TlJRb7FUlKyUatISsdzo+P7UU1Gb1POdMruckepGwk9tIXQTftz2yBaT5JQovWvpSa6poJPuqgao+b9l5Aj/R+mLQIP4f6Q8Vb3g/5TB/TJxWGdZr9EQrmn99fwKtTvAZGU7wzS7GNpZpDm2JgCrr8wrmPoo54UqGampFIeS9ojXjc4E2yI06bq/4DRoUAc0nVnng4k6p7Ks0+j/S8z9V+NZ5dhmrJUM/y7JTJeRtnJ2TSYJvsFq3CQt/vnfqmQXt5KlpuRcIvDAmhnn2E0t9BJ3SvB/SfLWhuOWNiNVZ+h28g4wlwUp00w95si43rZ3r6+fUIEdgOZbQAsyFRRvBR6dla8KCzRdslar7WS+a5HFb39peIAmG7uZTHVm17Czxju4m6bayz8e7J40DzqM0jr0bmv9PmPvk6y5z57HU8wdTDHeiUJvBMAM4+0CpoAZ4BPgJeAYEAHmgAUgAHiAj4AVAGORtwd4AVgC3gEmgBBwCPgMWANOAQ8AbwBHgHuAp4D3gLuARwoGmNUizF/j4yDC5BWM1kNvvlxFA8xikRrBxHIUhutFMBlgQoshhPphGAXe/OggKqqb2cibxwuEXjUcQjccxi5eFRL1fDSbKrUhy2CMb2aLyepkegDWsBwPlrVC0/kLHmeCBQ=='))
f=open('handcrafted-pyc.pyc','wb')
f.write(pyc)
f.close()

尝试运行pyc文件,提示bad magic number
用010editor 补齐magic number
img
用uncompyle6反编译提示失败,文件中有pyc字节码
img
img
img
首先了解一下字节码结构
更多可以查看这篇博客死磕python字节码
源码行号 | 跳转注释符 | 指令在函数中的偏移 | 指令符号(助记符) | 指令参数 | 实际参数值

starts_line(源码行号):以此操作码开头的行(如果有),否则 None
is_jump_target(跳转注释符):True 如果其他代码跳转到这里,否则 False
Offset(指令在函数中的偏移):字节码序列中操作的起始索引
opcode:操作的数字代码,对应于下面列出的操作码值和操作码集合中的字节码值。
opname(指令符号(助记符)):人类可读的操作名称
arg(指令参数):操作的数字参数(如果有),否则 None
argval:解析的 arg 值(如果已知),否则与 arg 相同
Argrepr(实际参数值):操作参数的人类可读描述

例如第一行的1 0 LOAD_GLOBAL 0 ‘chr’表示
该字节码在源码中对应一行,没有其他代码跳转到这里,偏移为0,助记符为LOAD_GLOBAL,指令参数为0,操作参数对应的实际值为’chr’
列举几个常见助记符

  • LOAD_CONST加载const变量,比如数值、字符串等等,一般用于传给函数的参数
  • LOAD_FAST一般加载局部变量的值,也就是读取值,用于计算或者函数调用传参等。
  • STORE_FAST一般用于保存值到局部变量。
  • LOAD_GLOBAL用来加载全局变量,包括指定函数名,类名,模块名等全局符号。
  • STORE_GLOBAL用来给全局变量赋值。
  • POP_JUMP_IF_FALSE表示条件结果为FALSE就跳转到目标偏移指令。
  • JUMP_FORWARD直接跳转到目标偏移指令。
    差不多了解完字节码,我们直接开始分析,先看第一段
 L.   1         0  LOAD_GLOBAL           0  'chr'
                3  LOAD_CONST               108
                6  CALL_FUNCTION_1       1  None #chr(108)l
                9  LOAD_GLOBAL           0  'chr'
               12  LOAD_CONST               108
               15  CALL_FUNCTION_1       1  None #chr(108)l
               18  LOAD_GLOBAL           0  'chr'
               21  LOAD_CONST               97
               24  CALL_FUNCTION_1       1  None #chr(97)a
               27  LOAD_GLOBAL           0  'chr'
               30  LOAD_CONST               67
               33  CALL_FUNCTION_1       1  None #chr(67)c
               36  ROT_TWO          #交换栈顶两个字符变成'l'和'l'    
               37  BINARY_ADD       #栈顶两个字符相加变成'll'
               38  ROT_TWO          #交换栈顶两个字符变成'a'和'll'
               39  BINARY_ADD       #栈顶两个字符相加变成'all'
               40  ROT_TWO          #交换栈顶两个字符变成'c'和'all'
               41  BINARY_ADD       #栈顶两个字符相加变成'call'

第一段字节码操作完栈顶为'call'
可以看到接下来的每一段字节码都差不多类似操作
最后字节码再用
PRINT_ITEM
PRINT_NEWLINE_CONT
输出栈顶内容,那我们只要模拟该过程就行

def binary_add(stack):
    tos = stack.pop()
    tos1 = stack.pop()
    stack.append(tos1+tos)
    return stack

def rot_two(stack):
    tos = stack.pop()
    tos1 = stack.pop()
    stack.append(tos)
    stack.append(tos1)
    return stack

with open("out.py", "r") as fp:
    lines = fp.readlines()
flag = ''
stack = []

for line in lines:
    if "LOAD_CONST" in line:
        line = line.split()[-1]
        if line.isdigit():
            stack.append(chr(int(line)))
        else:
            stack.append(0)# 如果不是数字的话,栈中添0。代码333行中出现了None,即添加空字符常量
    else:
        if "BINARY_ADD" in line:
            stack = binary_add(stack)
        elif "ROT_TWO" in line:
            stack = rot_two(stack)
print(stack)

img

exp

完整exp
import zlib,base64
pyc=zlib.decompress(base64.b64decode('eJyNVktv00AQXm/eL0igiaFA01IO4cIVCUGFBBJwqRAckLhEIQmtRfPwI0QIeio/hRO/hJ/CiStH2M/prj07diGRP43Hs9+MZ2fWMxbnP6mux+oK9xVMHPFViLdCTB0xkeKDFEFfTIU4E8KZq8dCvB4UlN3hGEsdddXU9QTLv1eFiGKGM4cKUgsFCNLFH7dFrS9poayFYmIZm1b0gyqxMOwJaU3r6xs9sW1ooakXuRv+un7Q0sIlLVzOCZq/XtsK2oTSYaZlStogXi1HV0iazoN2CV2HZeXqRQ54TlJRb7FUlKyUatISsdzo+P7UU1Gb1POdMruckepGwk9tIXQTftz2yBaT5JQovWvpSa6poJPuqgao+b9l5Aj/R+mLQIP4f6Q8Vb3g/5TB/TJxWGdZr9EQrmn99fwKtTvAZGU7wzS7GNpZpDm2JgCrr8wrmPoo54UqGampFIeS9ojXjc4E2yI06bq/4DRoUAc0nVnng4k6p7Ks0+j/S8z9V+NZ5dhmrJUM/y7JTJeRtnJ2TSYJvsFq3CQt/vnfqmQXt5KlpuRcIvDAmhnn2E0t9BJ3SvB/SfLWhuOWNiNVZ+h28g4wlwUp00w95si43rZ3r6+fUIEdgOZbQAsyFRRvBR6dla8KCzRdslar7WS+a5HFb39peIAmG7uZTHVm17Czxju4m6bayz8e7J40DzqM0jr0bmv9PmPvk6y5z57HU8wdTDHeiUJvBMAM4+0CpoAZ4BPgJeAYEAHmgAUgAHiAj4AVAGORtwd4AVgC3gEmgBBwCPgMWANOAQ8AbwBHgHuAp4D3gLuARwoGmNUizF/j4yDC5BWM1kNvvlxFA8xikRrBxHIUhutFMBlgQoshhPphGAXe/OggKqqb2cibxwuEXjUcQjccxi5eFRL1fDSbKrUhy2CMb2aLyepkegDWsBwPlrVC0/kLHmeCBQ=='))
f=open('handcrafted-pyc.pyc','wb')
f.write(pyc)
f.close()
def binary_add(stack):
    tos = stack.pop()
    tos1 = stack.pop()
    stack.append(tos1+tos)
    return stack

def rot_two(stack):
    tos = stack.pop()
    tos1 = stack.pop()
    stack.append(tos)
    stack.append(tos1)
    return stack

with open("out.py", "r") as fp:
    lines = fp.readlines()
flag = ''
stack = []

for line in lines:
    if "LOAD_CONST" in line:
        line = line.split()[-1]
        if line.isdigit():
            stack.append(chr(int(line)))
        else:
            stack.append(0)# 如果不是数字的话,栈中添0。代码333行中出现了None,即添加空字符常量
    else:
        if "BINARY_ADD" in line:
            stack = binary_add(stack)
        elif "ROT_TWO" in line:
            stack = rot_two(stack)
print(stack)

flag

hitcon{Now you can compile and run Python bytecode in your brain!}

[XSCTF联合招新赛2022]toddler_regs

shift+F12定位到flag
img
img
flag形式就是flag{aXp0int[7 * dword_14001FB90]_1s_n1c3_but_aXp0intjnu[10 * dword_14001FB94]_is_we1rd}
关键就是找到aXp0int[7 * dword_14001FB90]和aXp0intjnu[10 * dword_14001FB94]
这个函数里可以看到dword_14001FB94赋值为184
那么只要用aXp0intjnu的首地址加上10*184即加上0x730就可以找到aXp0intjnu[10 * dword_14001FB94]的值
img
可以看到首地址为14001E1C0
img
用G键快捷跳转至14001E8F0
img
获得aXp0intjnu[10 * dword_14001FB94]的值为Xp0intJNU
img
接下来我们寻找aXp0int[7 * dword_14001FB90]
用X键交叉引用dword_14001FB90
可以看到只有一个W类型(write)的引用,这肯定是对其的赋值,直接跳转
img
dword_14001FB90被赋值为23
img
同样的方法aXp0int首地址为14001E000
加上7 * 23即加上0xA1
img
跳转到14001E0A1,aXp0int[7 * dword_14001FB90]的值即为Xp0int
img
组合一下得到flag

flag

flag{Xp0int_1s_n1c3_but_Xp0intJNU_is_we1rd}

posted @ 2023-07-11 23:16  Tree_24  阅读(92)  评论(0编辑  收藏  举报