Loading

攻防世界-难度1- xxxorrr

攻防世界-逆向-难度1
根据提示应该是异或加密,找到密文和密钥,再异或回去就得到原文。
参考
https://blog.csdn.net/qq_63699339/article/details/130657034
官方wp

逆向解法

梳理一下程序执行逻辑
1.在main函数之前的init-array段首先执行了sub84A

在 ELF (Executable and Linkable Format) 文件中,Initialization Function Table 是一种特殊的数据结构,用于存储在程序启动时(在 main 函数执行之前)需要调用的一系列初始化函数的地址。这个机制允许程序或库执行必要的初始化任务,例如设置全局变量的初始状态、注册回调函数、初始化硬件设备或执行其他任何启动前准备工作。
如果 sub_840 的地址被包含在 ELF 的 Initialization Function Table 中,那么它会在程序的主逻辑开始执行之前被自动调用。这种自动调用是由程序的启动代码(通常是由编译器和链接器自动生成的一部分)负责的,该代码会遍历 Initialization Function Table 中的所有条目,并按照它们出现的顺序调用每个函数

image.png
2.进行了第一次异或处理
image.png
3.再来看main函数,sub_A90函数是做什么的
image.png
4.点进去
image.png
5.查一下_cxa_atexit的资料后就很清楚了,_cxa_atexit在exit函数中注册进程退出回调函数来实现析构
简单理解就是执行exit退出,会调用一个回调函数,这个回调函数就是sub916
image.png
6.再回到main函数,流程逻辑就明确了
image.png

整个程序对s1进行两次异或,第一次的密钥是(2 * i + 65) , 第二次的密钥是 s2[i],各循环33次

分析程序执行逻辑

ida64打开,字符串表看一下有没有什么线索
image.png
猜测这串字符跟flag有关,ctrl+x查看引用
image.png
有三个函数引用了,逐个查看

unsigned __int64 sub_84A()
{
    signed int i; // [rsp+Ch] [rbp-14h]
    unsigned __int64 v2; // [rsp+18h] [rbp-8h]

    v2 = __readfsqword(0x28u);
    for ( i = 0; i <= 33; ++i )
        s1[i] ^= 2 * i + 65;
    return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 sub_916()
{
    unsigned __int64 v1; // [rsp+8h] [rbp-8h]

    v1 = __readfsqword(0x28u);
    if ( !strcmp(s1, s2) )
        puts("Congratulations!");
    else
        puts("Wrong!");
    return __readfsqword(0x28u) ^ v1;
}
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
    signed int i; // [rsp+Ch] [rbp-34h]
    char s[40]; // [rsp+10h] [rbp-30h]
    unsigned __int64 v6; // [rsp+38h] [rbp-8h]

    v6 = __readfsqword(0x28u);
    sub_A90(sub_916, a2, a3);
    fgets(s, 35, stdin);
    for ( i = 0; i <= 33; ++i )
        s1[i] ^= s[i];
    return 0LL;
}

可以看到对s1(“qasxcytgsasxcvrefghnrfghnjedfgbhn”)处理了两次

for ( i = 0; i <= 33; ++i )
    s1[i] ^= 2 * i + 65;

for ( i = 0; i <= 33; ++i )
    s1[i] ^= s[i];

由此可得:

s1 = 'qasxcytgsasxcvrefghnrfghnjedfgbhn'
s2=[ 0x56, 0x4E, 0x57, 0x58, 0x51, 0x51, 0x09, 0x46, 0x17, 0x46, 
  0x54, 0x5A, 0x59, 0x59, 0x1F, 0x48, 0x32, 0x5B, 0x6B, 0x7C, 
  0x75, 0x6E, 0x7E, 0x6E, 0x2F, 0x77, 0x4F, 0x7A, 0x71, 0x43, 
  0x2B, 0x26, 0x89, 0xFE, 0x00]

for i in range(0,33):
    print(chr(ord(s1[i]) ^ (2 * i + 65) ^ s2[i]), end='')

总结

  1. ELF文件存在Initialization Function Table 数据结构,里面定义的函数会先于main函数被执行。
  2. _cxa_atexit是exit执行前的时刻,调用传入的回调函数,实现析构。__cxa_atexit 主要用于C++环境中,以确保全局和静态对象的析构函数能够正确地被调用。
posted @ 2024-04-28 22:54  _rainyday  阅读(44)  评论(0编辑  收藏  举报