RE逆向基础知识及常见题型

通用寄存器

  • FAX: (针对操作数和结果数据的)累加器
  • EBX: (DS段的数据指针)基址寄存器
  • ECX: (字符串和循环操作的)计数器
  • EDX: (I/O指针)数据寄存器
  • ESI: (字符串操作源指针)源变址寄存器
  • EDI: (字符串操作目的指针)目的变址寄存器
  • EBP: (SS段内存数据指针)存储基址指针寄存器;栈顶指针寄存器
  • ESP: (SS段中栈指针)栈指针寄存器指向栈顶

段寄存器

  • CS: 代码段寄存器
  • SS: 栈段寄存器
  • DS: 数据段寄存器
  • FS: 附加段寄存器
  • ES: 附加段寄存器
  • GS: 效果段寄存器

程序状态与控制寄存器

  • EFLAGS:标志寄存器,32个位元的01控制
  • ZF(零标志器,运算结果为0时置1)
  • CF(进位标志,运算结果向最高位以上进位时置1)
  • OF(溢出标志)
  • AF(辅助进位标志,运算结果在第3位的时候置1)
  • SF(符号标志,有符号整型的符号位为1时置1)

指令指针寄存器

  • EIP / RIP:保存CPU要执行的指令地址

常用指令

操作码 目的操作数 源操作数

  • PUSH/POP:压栈/出栈
  • PUSHA/POPA 、 PUSHAD/POPAD
  • MOV/CALL/RET/LEA/INT/EMD:传送 / 调用 / 返回 / 加载 / 中断 / 结束
  • CMP/TEST:比较/测试(结果丢弃,只修改标志位寄存器)
  • JMP系列跳转指令
  • ADD/SUB/SHL/SHR/ROL/ROR:加 / 减 / 逻辑左移 / 逻辑右移 / 循环左移 / 循环右移
  • INC/DEC :加一 / 减一
  • MUL/IMUL:无符号乘法、整数乘法
  • DIV/IDIV:无符号除法、整数除法
  • AND/XOR/OR/NOT:与 / 异或 / 或 / 取反

栈帧

PUSH EBP          ;函数开始
MOV  EBP,ESP      ;将栈顶地址存入EBP中

....              ;函数执行,期间EBP地址不变

MOV  ESP,EBP      ;基准点地址给到ESP
POP EBP           ;栈状态恢复,弹出EBP
RETN              ;

寻址方式

  • 寄存器寻址、立即寻址、寄存器间接寻址、基址寻址 …

IDA使用

IDA的常用快捷键

# F系列【主要是调试状态的处理】
F2 添加/删除断点
F4 运行到光标所在位置
F5 反汇编
F7 单步步入
F8 单步跳过
F9 持续运行直到输入/断点/结束
shift系列【主要是调出对应的页面】
shift+F1 Local types
shift+F2 execute scripts【常用】
shift+F3 Functions
shift+F4 Names
shift+F5 Signatures
shift+F7 Segments
shift+F8 Segments registers
shift+F9 Structures
shift+F10 Enumerations
shift+F11 Type libraries
shift+F12 Strings【常用】
Shift+E 导出数据【常用】

# 单字符系列【基本是数据处理转换相关】【这些都比较常用】
G 按地址查找
D 将字符串等元素转为数据
N 重命名(函数名、变量名等)
Y 修改变量类型等(比如int改char等等)
H decimal 数据的进制快速转换
A 将数据转变为字符串类型
C code(将数据转变为汇编代码,分为自动和强制执行)
U undefined(将字符串转变为原始数据)
X 交叉引用(反汇编页面)
P 选中位置识别为函数

# Ctrl、Alt系列
Ctrl+F 搜索【常用】
Ctrl+X 交叉引用(汇编页面)【常用】
Alt+T 查找Text
Ctrl+T 查找下一个text
Alt+C Next Code
Ctrl+D Next Data
Ctrl+Z 撤销
Ctrl+Shift+Z 恢复
Alt+K 修改堆栈值

# else
/ 添加注释 or 右键选择edit comment【常用】
\ hide cast,隐藏/显示一些变量类型注解
Ins 添加区块注释

NSSCTF RE1

分析汇编语言


.text:0000000000401550                 push    rbp
.text:0000000000401551                 mov     rbp, rsp
.text:0000000000401554                 sub     rsp, 90h
.text:000000000040155B                 call    __main
.text:0000000000401560                 lea     rcx, Buffer     ; "input your flag:"  //打印提示信息 “input your flag:”,提示用户输入字符串。
.text:0000000000401567                 call    puts
.text:000000000040156C                 lea     rax, [rbp+Str]
.text:0000000000401570                 mov     rdx, rax
.text:0000000000401573                 lea     rcx, Format     ; "%s"
.text:000000000040157A                 call    scanf  //通过 scanf 函数读取用户输入的字符串,存储在 [rbp+Str] 的内存位置。
.text:000000000040157F                 lea     rax, [rbp+Str]
.text:0000000000401583                 mov     rcx, rax        ; Str
.text:0000000000401586                 call    strlen  //调用 strlen 函数获取输入字符串的长度,并与 0x23 进行比较。如果长度不等于 0x23,则程序直接返回 0,否则继续执行。
.text:000000000040158B                 cmp     rax, 23h ; '#'
.text:000000000040158F                 jz      short loc_40159B
.text:0000000000401591                 mov     eax, 0
.text:0000000000401596                 jmp     loc_40162B
.text:000000000040159B ; ---------------------------------------------------------------------------
.text:000000000040159B
.text:000000000040159B loc_40159B:                             ; CODE XREF: main+3F↑j
.text:000000000040159B                 mov     [rbp+var_4], 0  //初始化一个循环变量 [rbp+var_4] 为 0,作为字符串的索引
.text:00000000004015A2
.text:00000000004015A2 loc_4015A2:                             ; CODE XREF: main+C8↓j
.text:00000000004015A2                 cmp     [rbp+var_4], 22h ; '"'  //进入一个循环,循环变量从 0 到 0x22
.text:00000000004015A6                 jg      short loc_40161A
.text:00000000004015A8                 mov     eax, [rbp+var_4]
.text:00000000004015AB                 cdqe
.text:00000000004015AD                 movzx   eax, [rbp+rax+Str]  //取出 [rbp+Str] 中索引为 [rbp+var_4] 的字符,与 0x52 进行异或运算,再存回原位置
.text:00000000004015B2                 xor     eax, 52h
.text:00000000004015B5                 mov     edx, eax
.text:00000000004015B7                 mov     eax, [rbp+var_4]
.text:00000000004015BA                 cdqe
.text:00000000004015BC                 mov     [rbp+rax+Str], dl
.text:00000000004015C0                 mov     eax, [rbp+var_4]
.text:00000000004015C3                 cdqe
.text:00000000004015C5                 movzx   eax, [rbp+rax+Str]  // 取出异或后的字符,加上 0x5,再存回原位置
.text:00000000004015CA                 add     eax, 5
.text:00000000004015CD                 mov     edx, eax
.text:00000000004015CF                 mov     eax, [rbp+var_4]
.text:00000000004015D2                 cdqe
.text:00000000004015D4                 mov     [rbp+rax+Str], dl  
.text:00000000004015D8                 mov     eax, [rbp+var_4]
.text:00000000004015DB                 cdqe
.text:00000000004015DD                 movzx   eax, [rbp+rax+Str] //再次取出加 0x5 后的字符,与 res 数组中对应索引的值进行比较
.text:00000000004015E2                 movsx   eax, al
.text:00000000004015E5                 mov     edx, [rbp+var_4]
.text:00000000004015E8                 movsxd  rdx, edx
.text:00000000004015EB                 lea     rcx, ds:0[rdx*4]
.text:00000000004015F3                 lea     rdx, res
.text:00000000004015FA                 mov     edx, [rcx+rdx]
.text:00000000004015FD                 cmp     eax, edx
.text:00000000004015FF                 jz      short loc_401614  
.text:0000000000401601                 lea     rcx, aWrong     ; "Wrong!"  //如果比较不相等,打印 “Wrong!” 并返回 0;如果相等,将循环变量加 1,继续循环。
.text:0000000000401608                 call    puts
.text:000000000040160D                 mov     eax, 0
.text:0000000000401612                 jmp     short loc_40162B
.text:0000000000401614 ; ---------------------------------------------------------------------------
.text:0000000000401614
.text:0000000000401614 loc_401614:                             ; CODE XREF: main+AF↑j
.text:0000000000401614                 add     [rbp+var_4], 1
.text:0000000000401618                 jmp     short loc_4015A2
.text:000000000040161A ; ---------------------------------------------------------------------------
.text:000000000040161A
.text:000000000040161A loc_40161A:                             ; CODE XREF: main+56↑j
.text:000000000040161A                 lea     rcx, aGood      ; "Good!"  //如果循环正常结束,即输入的字符串经过异或和加 0x5 操作后,与 res 数组完全相同,则打印 “Good!” 并返回 0。


.text:0000000000401621                 call    puts
.text:0000000000401626                 mov     eax, 0
.text:000000000040162B
.text:000000000040162B loc_40162B:                             ; CODE XREF: main+46↑j
.text:000000000040162B                                         ; main+C2↑j
.text:000000000040162B                 add     rsp, 90h
.text:0000000000401632                 pop     rbp
.text:0000000000401633                 retn
.text:0000000000401633 main            endp


hint = 0x21,0x6,0x6,0x16,0xb,0x19,0x2e,0x65,0x35,0x6a,0x6f,0x38,0x36,0x84,0x70,0x3b,0x39,0x65,0x38,0x35,0x84,0x6f,0x36,0x3c,0x6a,0x38,0x68,0x84,0x66,0x70,0x3b,0x38,0x6a,0x36,0x34,

EXP

data = [0x21,0x6,0x6,0x16,0xb,0x19,0x2e,0x65,0x35,0x6a,0x6f,0x38,0x36,0x84,0x70,0x3b,0x39,0x65,0x38,0x35,0x84,0x6f,0x36,0x3c,0x6a,0x38,0x68,0x84,0x66,0x70,0x3b,0x38,0x6a,0x36,0x34,
       ]

print("".join([
    chr((i-5)^0x52) for i in data
]))

NSSCTF{2b78ac-9df2ab-8ce7a1-39da7c}

NSSCTF RE2

使用IDA打开程序,找到main函数按F5将汇编语言转换成伪代码

双击enc查看其内容,然后使用shift+E将十六进制数提取出来

EXP

s = [0xc,0xc,0xc,0xc,0xc,0xc,0x41,0x25,0x32,0x3c,0x2c,0x25,0x3b,0x18,0x2c,0x36,0x45,0x42,0x2e,0x42,0x18,0x27,0x27,0x20,0x3f]
key = 'NSSCTF'
for i in range(len(s)):
    print(chr((s[i] - 12) ^ ord(key[i%6])),end='')

NSSCTF{Just_a_simple_XOR}

NSSCTF RE3

使用IDA打开程序后,按F5快捷键进行反汇编

双击aesEncrypt函数查看其内容

继续查看keyExpansion函数

进入keyExpansion函数内部后查看S中值

shift+E将数据提取出来

from Crypto.Cipher import AES 
from string import printable

data = [
    0xF3, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x8A, 0x00, 
    0x00, 0x00, 0xED, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 
    0xCE, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0xE2, 0x00, 
    0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 
    0x23, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x00, 0x00, 0xDC, 0x00, 
    0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 
    0xA4, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x6A, 0x00, 
    0x00, 0x00, 0x7B, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 
    0xE0, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x7C, 0x00, 
    0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 
    0x30, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xBC, 0x00, 
    0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x00, 0x00, 
    0x99, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00
]
print(len(data))

# 将data中每4个字节组合成一个16进制字符串
out = []
for i in range(0,len(data),4):
    out.append(  hex(data[i])[2:].upper())

print(len(out))
s = "".join(out)

def AES_DE(key,data):
    data = bytes.fromhex(data)  # 将16进制字符串转为字节串
    print(data.hex())
    key = key.encode('utf-8')   # 将密钥转为字节串
    print(key.hex())
    cipher = AES.new(key,AES.MODE_ECB)  # 创建AES-ECB解密器
    return cipher.decrypt(data)         # 解密

print("RE")
print(AES_DE("1234567890123456",s))   # 使用密钥"1234567890123456"解密密文s

def AES_EN(key,data):
    data = bytes.fromhex(data)
    print(data.hex())
    key = key.encode('utf-8')
    print(key.hex())
    cipher = AES.new(key,AES.MODE_ECB)
    return cipher.encrypt(data)

print("FRONT ... Ignore because cant and meaningless")

NSSCTF{d3b7aff970c9ac0a7b9f0044}

NSSCTF RE4

将主函数转换成伪代码,查看其逻辑结构,发现是一个简单的异或加密

exp

encode="NRQ@PC}?m9kni;k7v&%rq-t!zz{+}|xzA@@@@G@Z"
flag=""

for i in range(len(encode)):
    flag+=chr(ord(encode[i])^i)

print(flag)

运行逆向脚本还原flag

NSSCTF{8e0aee6e8f77ae8b6bca0aafeaabcdbf}

这题还有另一个解法,程序运行时就自动将flag还原,所以我们只需要在flag已经还原了后的位置打上断点就行了

先在这个位置打断点,然后运行程序,发现运行的时候会直接推出去,那是因为这个程序使用CheckDebug进行了反调试,一旦使用调试器运行就会退出

按Tab键返回汇编窗口,将这里打上断点

再次运行程序查看其程序流程走向,为了不让程序退出,我们需要将ZF的值改成0x1

这时终端会提示我们输入flag的值,我们这是只需要满足第一个判断条件,即flag长度不低于加密flag的长度,我们直接复制加密flag的值输入进去就可以了

回车,然后查看str中的值,成功获取flag

NSSCTF{8e0aee6e8f77ae8b6bca0aafeaabcdbf}

NSSCTF RE5

使用IDA打开程序查看主函数伪代码

主函数没有什么信息,我们在跳转到oo0o0o0o00o()函数查看一下内容,进入到oo0o0o0o00o()函数内后,发现是个异或加密

继续查看oo0o函数,发现是一个异或加密,继续往下看查看oo0oo0o0o0的内容

这里是一个生成伪随机数的代码,结合前面的几个加密函数,可以判段这是一个标准的RC4加密

RC4加密的话我们只要获取它的KEY和密文就可以解出flag了,先在这个if判断的位置打个断点,然后动态调试查看v6的内容获取key

KEY=‘Ricardo_M_lu’

然后再找一下密文,密文就在与你输入的flag比较的位置

mi=C2 B0 0E BE DB DF 95 2D CF 4B 74 41 F3 C9 43 A7 3C 70 C2 2F FF 8D 65 2C 5C

转换成十进制为:mi=194 176 14 190 219 223 149 45 207 75 116 65 243 201 67 167 60 112 194 47 255 141 101 44 92

获取密文和密钥后就可以写脚本解密了

EXP

#include<stdio.h> 
#include<stdlib.h>
#include<string.h> 
int init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
    
    int i = 0, j = 0;
    char k[256] = { 0 };
    unsigned char tmp = 0;
    for (i = 0; i < 256; i++) {
        s[i] = i;
        k[i] = key[i % Len_k];
    }
    for (i = 0; i < 256; i++) {
        j = (j + s[i] + k[i]) % 256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
    return 0; 
}


int rc4(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) 
{
    
    unsigned char s[256];
    init(s, key, Len_k);
    int i = 0, j = 0, t = 0;
    unsigned long k = 0;
    unsigned char tmp;
    
    for (k = 0; k < Len_D; k++) {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
        t = (s[i] + s[j]) % 256;
        Data[k] = Data[k] ^ s[t];
    }
    return 0; 
}
int main()
{
    
    unsigned char key[12] ;
    int a[12]={1,63,46,110,47,71,57,3,124,74,82,110,};
    int b[]={83,86,77,15,93,35,86,92,49,21,62,27,}; 
    for (int i=0;i<12;i++){
        key[i]=a[i]^b[i];
    }

    printf("%s\n",key);
    unsigned long key_len = sizeof(key) - 1;
    unsigned char qw[] = {194,176,14,190,219,223,149,45,207,75,116,65,243,201,67,167,60,112,194,47,255,141,101,44,92};
    rc4(qw, sizeof(qw), key, key_len);
    for (int i = 0; i < sizeof(qw); i++)
    { 
        printf("%c",qw[i]);  
    }
    return 0;
}

NSSCTF{Sh0w_m3_th3_m0n3y}

NSSCTF RE6

使用IDA打开程序,将主函数转换成伪代码,查看代码内容发现有输入约束,再看这些ascii码分辨对应这WASD,即上下左右,根据这些信息初步判断是

继续查看move()中的信息,这里是个生成地图的地方,那就可确定是迷宫题了,我们找一下地图

双击maze看一下

果然是地图

走出迷宫的操作路径就的md5是就是这题的flag,这个迷宫比较简单,所以直接看就行了

S ######
#  ## ##
##  # ##
###   ##
#   #  #
###### #
#      #
######E#

迷宫的路径是"dsdsdsddsdsss",再把路径转化为flag即可得到flag

NSSCTF{fb669a47680a17b3278ff8a68c80c36a}

NSSCTF RE7

使用查壳工具检查程序是否加壳,发现是一个upx壳,UPX壳是一个开源的压缩壳,既然是开源基本上就没啥秘密可言了。

使用FUPX进行脱壳

看一下加壳前的程序和加壳后的程序对比

然后仔细看脱壳后的代码发现if判断语句将这些变量进行了运算比较,我们只需要将式子逆推就可以还原flag了

exp

from sympy import symbols, Eq, solve  

# 定义变量  
v4, v19, v18, v17, v15, v7, v12, v16, v13, v5, v9, v14, v11, v10, v8, v6 = symbols('v4 v19 v18 v17 v15 v7 v12 v16 v13 v5 v9 v14 v11 v10 v8 v6')  

# 定义方程  
equations = [  
    Eq(7 * v4, 546),  
    Eq(2 * v19, 166),  
    Eq(6 * v18 + v17 + 7 * v15, 1055),  
    Eq(2 * v7 + v12 + 7 * v15 + v17 + 4 * v19 + 4 * v16 + 6 * v13 + 8 * v5, 3107),  
    Eq(4 * v16, 336),  
    Eq(2 * v19 + 7 * v15, 656),  
    Eq(2 * v7 + 3 * v9 + 3 * v14 + 6 * v13 + v12 + 5 * v11 + 16 * v10 + 6 * v8 + 8 * v5, 5749),  
    Eq(6 * v13, 606),  
    Eq(5 * v6 + v12, 652),  
    Eq(5 * v11 + 16 * v10 + 6 * v8, 3213),  
    Eq(2 * v7 + 3 * v9 + 24 * v10 + 5 * v11 + 3 * v14 + 6 * v13 + v12 + 6 * v8 + 8 * v5, 6717),  
    Eq(3 * v9, 285),  
    Eq(2 * v12 + 3 * v14 + 6 * v13 + 8 * v10 + 6 * v8 + 2 * v7 + 5 * v6 + 8 * v5, 4573),  
    Eq(5 * v6, 600),  
    Eq(v17 + 6 * v18 + 4 * v16 + 7 * v15 + 2 * v7, 1615),  
    Eq(v12 + 7 * v15 + 2 * v19 + 6 * v13 + 8 * v5, 2314)  
]  

# 求解方程  
solution = solve(equations)  

# 将结果添加到列表 li 中  
li = [solution[v] for v in [v4, v19, v18, v17, v16, v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5]]  

# 打印结果  
print("变量的值:", solution)  
print("假设值列表 li:", li)
li = [78, 83, 83, 67, 84, 70, 123, 101, 52, 115, 121, 95, 117, 112, 120, 125]
for i in li:
    print(chr(i),end="")

NSSCTF{e4sy_upx}

NSSCTF RE8

使用查壳工具查壳,未发现加壳

使用IDA打开程序,查看主函数伪代码,发现比对部分有base64编码字符串,应该是加密后的flag

主函数中调用了一个base64_encode函数,我们看一下里面的内容,是base64加密,但是我们不知道编码表,动态调试一下看看能不能将编码表生成出来

在主函数调用加密函数处打断点

查看base_chars中的内容

选中十六进制数据,按A键将其转换成ascii码,发现编码表确实被改了

有了编码表和密文写脚本还原flag

EXP

import base64

str1 = "tLntq1rgE1nTq18XC19Zmf9Lyxnzix0="

string1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/" #自定义base加密表
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

print(base64.b64decode(str1.translate(str.maketrans(string1, string2))))

NSSCTF RE9

将pyexe.exe使用pyinstxtractor-ng.py解析

打开解析后的文件夹pyexe.exe_extracted,将里面的main.py函数,使用pycdc.exe进行反编译

编译后得到如下内容

def caesar_cipher(text, shift):  
    # 定义一个函数 caesar_cipher,接受两个参数:text(要加密的文本)和 shift(位移量)  
    result = ''  # 初始化一个空字符串,用于存储加密后的结果  
    for char in text:  
        if char.isalpha():  # 检查字符是否为字母  
            start = ord('A') if char.isupper() else ord('a')  # 确定字母的起始 ASCII 码(大写字母或小写字母)    
            result += chr(((ord(char) - start) + shift) % 26 + start) # 计算加密后的字符,并将其添加到结果字符串中
            continue  
        result += char  # 如果字符不是字母,直接将其添加到结果中  

    return result  # 返回加密后的字符串  


def main():  
    # 定义主函数 main  
    flag = input('plz_input_your_flag:')  # 提示用户输入一个字符串(flag)  
    shift = 3  # 设置位移量为 3  
    encrypted_text = caesar_cipher(flag, shift)  # 调用 caesar_cipher 函数对输入的 flag 进行加密  
    if encrypted_text == 'QVVFWI{s9wkrq_Uh_1v_q0w_edG}':   # 检查加密后的文本是否与预定义的字符串匹配  
        print('congrulations!')  # 如果匹配,打印祝贺信息  
    else:  
        print('wrong')  # 如果不匹配,打印错误信息  

if __name__ == '__main__':  
    main()  # 如果该脚本是主程序,则调用 main 函数

根据代码中的关键变量shift(偏移量)可以知道,这是个凯撒加密,编写exp逆向解出flag

exp

D = 'QVVFWI{s9wkrq_Uh_1v_q0w_edG}'  # 定义一个字符串 D,包含字母和其他字符  
shift = 3  # 定义一个变量 shift,表示字母的位移量为 3  

for i in D:  # 遍历字符串 D 中的每一个字符  
    if i.isalpha():  # 检查当前字符 i 是否是字母  
        print(chr(ord(i)-shift), end="")  # 如果是字母,计算其 ASCII 值并减去 shift,然后转换回字符并打印,不换行  
    else:  # 如果当前字符不是字母  
        print(i, end="")  # 直接打印该字符,不换行

NSSCTF RE10

先将程序查壳,检查后发现有UPX壳

使用壳-UPX脱壳,脱完壳后使用ida打开程序,阅读伪代码,发现没什么主要的东西,我们查看调用的函数里面有什么

进入decrypt函数,发现encrypt被异或加密了,我们看一下encrypt的密文

双击encrypt,看到了encrypt被加密后的内容,写个idc脚本解密

idc脚本

auto addr = 0x401530; 
auto i = 0; 
for(i; i < 213; i = i+1) {
PatchByte(addr+i,Byte(addr+i)^0x90); 
}

shift+f2运行脚本

解密后的内容

选中解密后的内容,按c键将其转换成代码

转换后的结果

光标放到箭头的位置,再按p转换成函数

这个时候我们就可以使用F5大法反汇编了

反汇编后的代码内容,可以看出来这写时TEA加密,TEA加密的核心在于每轮使用密钥的不同部分对数据块进行多次简单的数学运算(主要是加法和异或)。明文被分为两个32位部分(L和R),每轮分别进行混合和变换,经过多轮处理后,输出密文。

再主函数中题目已经把密钥和密文给我们了,所以可以写脚本解密了

exp

#include <stdint.h>
#include <stdio.h>
#include <string.h>

void decrypt(uint32_t v[2], uint32_t key[4]) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;
    uint32_t delta = 0x9e3779b9;

    for (i = 0; i < 32; i++) {
        v1 -= ((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3]);
        v0 -= ((v1 << 4) + key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + key[1]);
        sum -= delta;
    }

    v[0] = v0;
    v[1] = v1;
}

int main() {
    uint32_t ciphertext[6] = {0x52286ECB,0x5A1EC44F,0xF284265E,0xF967E7D6,0x46dd0938,0x0a6950d3}; //密文位置

    uint32_t key[4] = {0x01234567, 0x89ABCDEF, 0xFEDCBA98, 0x76543210};//key

    for(int i = 0; i < 3; i++){
        uint32_t temp[2] = {ciphertext[i*2],ciphertext[i*2+1]};
        decrypt(temp, key);
        printf("Decrypted String: %s\n", (char *)temp);
    }
    return 0;
}

NSSCTF{9dxc9x2d7g77d5s1}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/928749.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

APM装机教程(四):山鹰H743飞控四旋翼装机

文章目录 前言一、飞控说明书二、接线三、参数设置四、电机接线和转向 前言 固件版本&#xff1a;Copter 4.5.7 地面站&#xff1a;QGC 遥控器&#xff1a;云卓T10 飞控&#xff1a;山鹰H743 GPS&#xff1a;微空M9 这个飞控的原理图是开源的&#xff0c;网盘链接&#xff1a;…

实验四:MyBatis 的关联映射

目录&#xff1a; 一 、实验目的&#xff1a; 熟练掌握实体之间的各种映射关系。 二 、预习要求&#xff1a; 预习数据库原理中所讲过的一对一、一对多和多对多关系 三、实验内容&#xff1a; 1. 查询所有订单信息&#xff0c;关联查询下单用户信息(注意&#xff1a;因为一…

【C#设计模式(17)——迭代器模式(Iterator Pattern)】

前言 迭代器模式可以使用统一的接口来遍历不同类型的集合对象&#xff0c;而不需要关心其内部的具体实现。 代码 //迭代器接口 public interface Iterator {bool HashNext();object Next(); } //集合接口 public interface Collection {Iterator CreateIterator(); } //元素迭…

MySQL 主从同步一致性详解

MySQL主从同步是一种数据复制技术&#xff0c;它允许数据从一个数据库服务器&#xff08;主服务器&#xff09;自动同步到一个或多个数据库服务器&#xff08;从服务器&#xff09;。这种技术主要用于实现读写分离、提升数据库性能、容灾恢复以及数据冗余备份等目的。下面将详细…

Redis4——持久化与集群

Redis4——持久化与集群 本文讲述了1.redis在内存占用达到限制后的key值淘汰策略&#xff1b;2.redis主从复制原理&#xff1b;3.redis的哨兵模式&#xff1b;4.redis集群模式。 1. 淘汰策略 设置过期时间 expire key <timeout>只能对主hash表中的键设置过期时间。 查…

矩阵转置        ‌‍‎‏

矩阵转置 C语言代码C 语言代码Java语言代码Python语言代码 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 输入一个n行m列的矩阵A&#xff0c;输出它的转置 A T A^T AT。 输入 第一行包含两个整数n和m&#xff0c;表示矩阵A的行数和列数。…

Linux 无界面模式下使用 selenium

文章目录 前言什么是无界面模式&#xff1f;具体步骤安装谷歌浏览器查看安装的谷歌浏览器的版本下载对应版本驱动并安装Python 测试代码 总结个人简介 前言 在 Linux 服务器上运行自动化测试或网页爬虫时&#xff0c;常常需要使用 Selenium 来驱动浏览器进行操作。然而&#x…

windows部署PaddleSpeech详细教程

windows安装paddlespeech步骤&#xff1a; 1. 安装vs c编译环境 对于 Windows 系统&#xff0c;需要安装 Visual Studio 来完成 C 编译环境的安装。 Microsoft C Build Tools - Visual Studio 2. 安装conda conda create -y -p paddlespeech python3.8 conda activate pad…

11.7【miniob】【debug】

这里的vector是实际值&#xff0c;而relation是指针&#xff0c;所以要解引用&#xff0c;*$1&#xff0c;并在最后调用其析构函数 emplace_back 和 push_back 都是用于在容器&#xff08;如 std::vector&#xff09;的末尾添加元素的方法&#xff0c;但它们的工作方式有所不同…

聊聊JVM G1(Garbage First)垃圾收集器

CMS的垃圾回收机制&#xff0c;为什么分为四步https://blog.csdn.net/genffe880915/article/details/144205658说完CMS垃圾回收器&#xff0c;必定要说到目前一般应用项目中都推荐的G1。G1在JDK1.7 update4时引入&#xff0c;在JDK9时取代CMS成为默认的垃圾收集器。它是HotSpot…

一篇文章教会你红外接收模块接收红外遥控信号,附STM32代码示例

目录 一、红外线的通讯原理&#xff1a; &#xff08;1&#xff09;发射端&#xff1a; &#xff08;2&#xff09;接收端&#xff1a; &#xff08;3&#xff09;红外线通信的脉冲频率&#xff1a; &#xff08;4&#xff09;红外线通信&#xff1a; 二、NEC协议介绍&am…

Ignis如何将Tokenization解决方案应用于RWA和实体经济

随着区块链技术的发展&#xff0c;代币化&#xff08;Tokenization&#xff09;逐渐成为连接数字经济与实体经济的重要桥梁。尤其是RWA&#xff08;真实世界资产&#xff09;的概念&#xff0c;近年来成为金融行业的热议话题。Ignis作为Jelurida公司推出的公链平台&#xff0c;…

Linux的用户和权限【Linux操作系统】

文章目录 Linux的用户切换用户普通用户暂时以root用户的权限执行指令如何把一个普通用户加入白名单? 新建用户 Linux权限权限的组成更改权限文件/目录权限的表示方法&#xff1a; umask粘滞位添加粘滞位的方法 Linux的用户 Linux下有两种⽤⼾&#xff1a;超级用户&#xff08…

【专题】计算机网络之运输层(传输层)

1. 运输层协议概述 1.1 进程之间的通信 (1) 运输层的作用 运输层提供进程间的逻辑通信。 运输层的屏蔽作用&#xff1a; 运输层向高层用户屏蔽了下面网络核心的细节&#xff08;如网络拓扑、所采用的路由选择协议等&#xff09;&#xff0c;使应用进程看见的就是好像在两个运…

【C#之WPF+OllamaSharpe实现离线AI对话】

一、前言 C#之WPFOllamaSharpe实现离线AI对话&#xff0c;调用Markdig格式化显示交互结果. 此程序默认你已经安装好了Ollama。 在运行前需要线安装好Ollama,如何安装请自行搜索 Ollama下载地址&#xff1a; https://ollama.org.cn Ollama模型下载地址&#xff1a; https:/…

LeetCode 力扣 热题 100道(十四)二叉树的中序遍历(C++)

给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 如下为代码&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullpt…

在Node.js局域网调试https的Vue项目

需求&#xff1a; 最近在测试在网页端&#xff08;HTML5&#xff09;调用移动设备的定位等权限功能&#xff0c;发现某些功能是必须保证域名在https下的否则会出现不正常现象。 解决&#xff1a; 1.在线生成和证书 访问&#xff1a;CSR文件生成工具-中国数字证书CHINASSL …

视频监控汇聚平台Liveweb视频安防监控实时视频监控系统操作方案

Liveweb国标GB28181视频平台是一种基于国标GB/T28181协议的安防视频流媒体能力平台。它支持多种视频功能&#xff0c;包括实时监控直播、录像、检索与回看、语音对讲、云存储、告警以及平台级联等功能。该平台部署简单、可扩展性强&#xff0c;支持全终端、全平台分发接入的视频…

如何利用内链策略提升网站的整体权重?

内链是谷歌SEO中常常被低估的部分&#xff0c;实际上&#xff0c;合理的内链策略不仅能帮助提升页面间的关联性&#xff0c;还可以增强网站的整体权重。通过正确的内链布局&#xff0c;用户可以更流畅地浏览你的网站&#xff0c;谷歌爬虫也能更快地抓取到更多页面&#xff0c;有…

DICOM MPPS详细介绍

文章目录 前言一、常规检查业务流程二、MPPS的作用三、MPPS的原理1、MPPS与MWL2、MPPS服务过程 四、MPPS的实现步骤1、创建实例2、传递状态 五、总结 前言 医院中现有的DICOM MWL(Modality Worklist)已开始逐渐得到应用&#xff0c;借助它可以实现病人信息的自动录入&#xff0…