MENU

bugku Reverse bingo

December 12, 2020 • Read: 609 • Reverse

听说BugKu上线了,从昨天下午做到了今天下午,正好一天时间,最后是做了87题,实在是做不动了,冲分就暂时告一段落,前面的题目还是比较水的。这里讲解一下花了我大概一个小时才做出来的题目,bingo
ranklist.png
题目是一个解锁包,解压得到一张图片。
bingo.png
刚开始的时候没看分类,以为是MISC题,然后找了半天隐写内容,都没做找到,但是这个文件这么大,肯定是有问题。
然后又仔细找了一下,结果发现了这样一段内容,
图片截图.png
看上去内容好像是EXE程序中才会有的,于是看了一下分类,好家伙,原来是re题。
百度了一下png文件尾
PNG (png),   
文件头:89504E47  文件尾:AE 42 60 82
搜索 AE 42 60 82
mz.png
这不就是熟悉的MZ文件头吗,用010 Editor提取出这一段内容。
并重命名为bingo.exe
error.png
结果报错了,随便找了一个exe文件,比对文件内容是否确实,发生少了PE文件头标识。
PE缺失.png
补上这一段内容。
ok.png
数据补上后直接打开运行,发现可以显示黑框,但是运行后直接退出,于是打开IDA分析一下
ida.png
ida打开后似乎认不出来文件的其他内容,动态调试后发现这一段内容会出现异常的情况。

pusha
mov     ecx, 3E000h
mov     ebx, 1000h
mov     ebx, 400000h
add     ebx, edx
xor     byte ptr [ebx], 22h
inc     ebx
popa
jmp     loc_408BE0

原因是edx的内容也是400xxxh,相加之后到了800xxx,超出了范围。
这里不知道是作者预期还是怎么的,反正应该是这个解密函数出现了问题。
但是看到这里应该就是一个xor解密(xor 0x22),所以直接在外部解密吧。

#define MAXKEY 5000
#define MAXFILE 1000
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
    char xor_key[MAXKEY], file_dir[MAXFILE];
    char* buf;
    //printf("xor key: ");
    //scanf("%s", xor_key);
    xor_key[0] = 0x22;
    xor_key[1] = 0;
    printf("file: ");
    scanf("%s", file_dir);
    FILE* fp = fopen(file_dir, "rb");
    strcat(file_dir, ".xor");
    FILE* fpw = fopen(file_dir, "wb+");
    if (fp && fpw)
    {
        fseek(fp, 0, SEEK_END);
        size_t size = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        buf = new char[size];
        fread(buf, sizeof(char), size, fp);
        for (size_t i = 0, keySize = strlen(xor_key); i < size; i++)
            buf[i] ^= xor_key[i % keySize];
        fwrite(buf, sizeof(char), size, fpw);
    }
    if (fp) fclose(fp);
    if (fpw) fclose(fpw);
    return 0;
}

解密文件后,得到文件bingo.exe.xor,观察文件信息,发现实际上只有.text段进行了异或加密,其他内容都没有加密。
从文件中大量的0x22内容也可以看出来(因为0x00 ^ 0x22 = 0x22)
cmp.png
从0xCC就可以知道,应该是解密对了,因为0xCC对应的是INT3断点,也就是当段未初始化的时候,vs debug模式下会赋值的内容。vs中的烫烫烫也是这么来的。
替换.text段的内容。
替换后.png
替换后得到的exe程序,直接运行当然还是不可以的,但是可以放到ida中解析各个函数了。
但是没有任何的符号信息,难以阅读。所以我还是打算调整程序让其可以正常运行。

打开ida后,定位到start处
patch.png
直接用Keypatch(ida插件)进行修改,让其直接跳到程序真正的入口点(jmp sub_408BE0)。
patch.png
修改后进行保存
canrun.png
发现程序以及可以成功运行。
重新载入后发现,接下来发现程序的符号信息就有了。
main.png
可以看出,程序对输入内容进行加密后与程序中off_443DC0(zaciWjV!Xm[_XSqeThmegndq)进行比对。
encode.png
这里的加密方法就是对你输入值(c)进行平方,然后再加上一个参数(b),最后解出来a。
满足关系式: a^2 + b^2 = c^2。
本来以为直接解密就好了,没想到这里还有一个函数_strrev(v6);
他的作用是把字符串信息倒置,所以最后显示的顺序也会变换。

由于这里sqrt还有个精度问题,我这里就不进行逆运算了,也就是
c = sqrt(a^2 + b^2)
直接编写程序爆破c的内容。

解密程序

#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;

int main()
{
    char s[] = "zaciWjV!Xm[_XSqeThmegndq";
    char e[] = "                        ";
    char* v6 = (char*)operator new(strlen(s) + 1);
    memset(v6, 0, strlen(s) + 1);

    for (int i = 0; i < strlen(s); i++)
    {
        v6[i] = 'a' + i;
        _strrev(v6);
    }
    for (int i = 0; i < strlen(s); i++) e[v6[i] - 'a'] = s[i];
    printf("%s\n", v6);
    printf("%s\n", e);
    int a2 = 0x34;
    for (int i = 0; i < strlen(s); ++i)
    {
        for (char t = 1; t < 0xFF; t++)
        {
            int v2 = (signed __int64)pow((double)a2, 2.0);
            signed int v3 = (unsigned __int64)(signed __int64)pow((double)t, 2.0);
            v3 -= v2;
            v6[i] = (signed __int64)(sqrt((double)v3) + 0.5);
            if (v6[i] == e[i])
            {
                printf("%c", t);
                break;
            }
        }
        --a2;
    }
    return 0;
}

运行后可以得到:
flag.png

flag{woc_6p_tql_moshifu},看到这个flag之后还是觉得挺开心的。

Last Modified: March 23, 2021
Archives QR Code Tip
QR Code for this page
Tipping QR Code
Leave a Comment

2 Comments
  1. Sapphire Sapphire

    大哥求教皇家马德里flag.png里面到底怎么弄

    1. Sapphire Sapphire

      @Sapphire已经搞出来了 谢谢