首页
社区
课程
招聘
[原创]2016腾讯游戏安全技术竞赛题PC第一题
发表于: 2022-4-23 09:22 10817

[原创]2016腾讯游戏安全技术竞赛题PC第一题

2022-4-23 09:22
10817

忘了从哪儿找到的这个题目,偶然得知,就尝试着弄一下。
2016腾讯游戏安全技术竞赛PC第一题

图片描述
结论:

​ 纵观全局,才知道原来序列号就是把用户名两次加密后,再Base64编码为字符串。

只是不同于一般常用的64个字符串罢了。

这里输出"helloworld",计算出来的序列号是"VASdBcsKGhNDMRwPXv85%61MNQR"

实际上,最后一个字符改成Q/R/S/T都是可以的。因为长度不是4的整数倍,使用了'*'填充

事后来看,尽量写得有条不紊,井井有条。
实际调试的时候,总是注意看寄存器的变化,真是非常的耗费精力。
注册机啥的,还真没接触过,毕竟,没有加密,也没加壳的程序,直接爆破可轻松多了。
不动手操作,只停留理论,觉得自己掌握了方法,就能一番风顺,无异于纸上谈兵,是不会有进步的。

​ 我们随便输入,点击注册,发现没有提示框之类的,只是单纯的提示注册失败。

使用OD一搜索,也没有相应的字符。

唯一有用的,或许就是这个了。

图片描述

64个字符,出现了好几次。猜想或许会使用base64编码的方式。

既然没有直接有用的信息,就只能从API下手了。

使用PE工具一看,好几个和text相关的API

感觉能用的就是GetWindowTextA,下断点一测试,毫无反应。

至于其他没导入的API,比如GetDlgItemTextA之类的,在一一尝试后,都没断下。说明获取文本不是用的这类API。

考虑到这是一个很明显的MFC程序,于是百度一搜索:MFC程序获取文本控件
MFC控件编程之按钮编辑框

这一篇可谓非常详尽了。这个注册机就用的GetDlgItem和消息循环的方式。

果然,在输入文本以后,点击注册,就断在了user32.GetDlgItem里面。

直接返回即可。

图片描述

返回到获取句柄的地方,啥也没干就返回了。

返回后继续看。

图片描述

果然,就是这样获取文本的。(获取控件句柄,再使用消息循环)

接下来,同样的方式获取序列号的文本。

然后esp+0x9C是用户名文本,esp+0x1A0是序列号文本。

获取了文本,就开始准备注册结果的字符串。

分别是 注册00000失败成功 。等下就把结果复制到前面4个0那里,组成最终的注册结果

图片描述

紧接着就是获取用户名的长度,限定为6-20位

紧随其后,就是对用户名的加密。开辟了0x14个字节的空间。

从esp+0x88开始,也就是用户名前面的0x14个字节

图片描述

这一段还是好理解的,原样的翻译了以下,虽然其中一些数据不知道来源,但是我们直接写死也是不影响结果。

随便输入文本试了试,算出来和注册机的结果是一样的,那就问题不大。

继续F8步过,发现获取密码长度的地方以及一些call,先不急着看call,直接走下去。

走到这里,来了一个大跳转。
图片描述
图片描述

通过观察寄存器的值,可以看见直接拼凑成了字符串注册失败。

没有任何其他的判断,直接 xor eax,eax,将eax置为0,就是注册失败。

因为成功在失败的后面,所以eax为1的时候,就显示注册成功。

走到取字符的地方,看见从其他地方跳转到这里,正巧 mov eax,1,也就是说那条路才是成功的道路,而我们之前跳转的地方,是没有任何回头的死路。

图片描述

不用调试,直接往上查看反汇编。

图片描述

可见好几个到同一目的地的跳转,然后跳转以后,都没有包含 mov eax,1的指令,可见,都是失败的。也就是这些jne,一个都不能跳。

翻译一下,也就是好几个并列条件

失败重来。这次注意看edx是如何来的

图片描述

edx = 0x2f65824,edi = 0x2f65820,感觉应该是两个地址,看下内存

图片描述

猜测这一段也是类似于取文本长度一样,从字节数组结尾的地方减去字节数组开始的地方,也就是字节数组的长度。

刚才输入的序列号是123456。我们直接Ctrl+F2重新启动,多输入几个字符,但是前面还是123456。

同样观察一下地址上的数据,可见前面部分保持一致。输入变长,这一段也变长,但是还不到0x14.我们继续加长。

当长度来到27位的时候,终于能继续正常往下走了。也就是限定密码长度为27.

正确跳转以后,就来到了这里。

图片描述

这一段的手法和第一次加密用户名类似啊,开辟0x24个字节的空间。

看循环里面,有用到之前加密过的用户名,也就是再次加密。

观察里面的数据。

这里面的数据,和我们之前判断序列号长度看见的数据很相似。于是再次重新运行

在判断长度的地方断下,并进去查看esi地址上的数据(只需要看0x14个字节即可),可见,和循环里面的数据是一样的。

当然,其实也不用看,因为中间没有修改edi的值,而esi也是从0开始,随着循环增大而变化。

这一段,还是可以翻译成C++代码的形式。

虽然中间也有一些不知道是什么的数据,但是观察运行后,发现写死就能正常运行,也就不管了。完全的翻译了一下,虽然后来发现,复制的数据完全没用到。
这个imux还挺麻烦的,直接写成一个函数了。

加密完成,来到了决胜的地方。

要同时满足这些条件,才能注册成功。

还是习惯性的翻译成高级语言吧。

把第二段加密后的total作为esp的开端,当作参数传进去。

first:

second:精简一下。

last:

精简再精简,最终可以通过二次加密的用户名求出正确的字节数组。

都到这里了,显然,未知的那一部分就是和密码有关的东西。

到这里,在二次加密的末尾,添加上这一段,就可以求出正确的加密后的序列号数组。

实践是检测真理的唯一标准。回到调试器里面,在用户名加密完成以后,用这一段替换esp+0x40后面的0x14字节,运行结束,注册成功。

到这里,离成功就很近了,接下来就需要分析序列号是如何加密的就好了。

首先,要找到在哪里用到了序列号。

可以直接在序列号那里使用硬件访问断点。
图片描述

不过没必要一上来就断下,因为在取序列号长度的地方会反复断下。

等运行到图示的位置,再使用硬件断点即可。

图片描述

直接F9运行,来到了不知道是哪里。

图片描述

通过观察,分析,知道这一段用来拷贝序列号。那么,拷贝后的内存地址就是我们需要关注的地方。

不断的F8或者直接运行到函数结束,不断的出CALL,终于回到了取长度后第一个CALL的下一句。所以,这个call就是用来拷贝序列号的。

留给我们的call也不多了,就这两个。

图片描述

需要注意的是,这个程序函数调用采取C的调用方式,堆栈由调用方进行平衡。

对堆栈的相关内容,可以参见MASM32汇编中关于栈的总结 - 念秋 - 博客园 (cnblogs.com)

虽然这里面没有关于清理堆栈的内容。

对这两个函数分别查看参数和运行结果。

第一个不太明显,但是第2个,从结果看来,貌似就是清理了一下内存。也就是清除了之前复制的序列号。清除,那就是善后工作了。

最后,也就剩这一个call可以加密序列号了。

这里面call很多,然后一堆循环。

进入这个call,也没有什么好的思路,一开始,追踪寄存器的值,反而搞得头昏脑涨。

不知从何处下手,那就先F8一步一步看看。

图片描述

走到这里,发现ebx指向复制后的序列号。然后对eax和ecx的操作都是对称的。

从ebx那个字节数组里面取出一个字节保存到(unsigned char*)(esp+0x18)[eax]处。

有比较,又有跳转,可以猜测是不是进入了循环。

这个复制完值,往下走,紧接着两个很远的跳转,暂时不清楚是什么。

图片描述

走到这里,发现参数来自序列号。

这个小的函数调用,不知道有什么用。翻译了一下,最后还是没用上。

一直F8走吧,走吧。又走到了上面那个对称的地方。

多走几次,发现esp+0x18上面变成了从序列号拷贝的4个字节。

图片描述

此时,来到了 cmp eax,4 而eax=4。就不会再进行刚才的循环了。

走下去,发现又是一个循环。

图片描述

也就是每次一个字符,进入call进行变化。也就是读取一个字节,修改,然后写回去。

这个进去以后,一堆常量还是什么的。

图片描述

在这个call之前,完全不知道是在干什么。

图片描述

通过堆栈,可以发现,这是一个3个参数的函数。其中两个参数是base64字符串和要转换的字符,另一个不知道是什么。

进去看看,不长,而且末尾非常类似。那就可能是根据运算结果从数组里面选择一个值回去。

尝试翻译,但是感觉有点费劲,而且翻译出来也没用。

虽然这个汇编代码是从高级语言编译出来的,但是再从汇编转为C++,就感觉翻译不出来啊。

不知道写得对不对,翻译出来都不想验证一下了。直接返回,发现转换的字符重新写回去了。

循环运行吧,循环结束,走到了这里。

图片描述

发现刚才的4个字节已经全部改变了。

图片描述

继续往下走。

图片描述

发现这一段,主要改变了3个字节的数据。

图片描述

非常的眼熟啊,之前已经看了好几遍了。

正是第二次用户名加密中拷贝的加密后的序列号。

既然出现再这里,那就代表没有别的地方来加密序列号了。至于这个数据写到哪里,我们不用管了。

我们只需要关心是不是每次运行到这里,出现的数据都是最后的加密结果。

直接在xor edi,edi的地方下个断点,直接F9运行。可以看见加密后的序列号不断的出现,每次都是转换为3个字节。
前有64个字符串的字符替换,后有4字节到3字节的压缩。我们可以猜测是否为base64解码的过程。

总结一下序列号的加密,就是4个字节,先转换一下,再经过上面的各种位操作,就得到了最终结果。

这一段的移位操作虽然有点长,但是输入输出都是明显的,也就很好翻译,翻译的同时注意看二进制串,希望就是期待的编码规则,这样可以省点力气。

运行结果。

成功的把0x35 0x36 0x37 0x38转换为了 0xD7 0x6D 0xF8

通过观察二进制,可以发现。输入的4字节和输出的3字节恰好满足base64编码的中间规则。38bit转换为46bit,每个bit高2位取0.
再不断的带入注册机的内存结果到程序,发现转换没问题,说明程序翻译得没错。
且都满足base64编解码的中间过程。

也就是上述的运算结果可以互相转换。

我们可以把之前自己求出来的加密后的字节数组带进去,反推出经过第一次字符转换后的字节数组。

也就是

字符串“1234” 字符转换为 "5678" ,再编码成了 0xD7 0x6D 0xF8

现在我们已经有了D7 6D F8 ,可以推出 "5678",接下来只需要观察字节转换的函数,看下如何变回"1234"即可。

不过也可以不用看了,这里已经确定是base64编码的一部分。那么之前那个函数大概率就是在base64字符串里面找下标的。
直接写个完整的base64编码,把我们求出来的加密后序列号带进去看看。

base64转换:

123456789012345678901234564

程序从"123456789012345678901234567"转换的字节数组,经过我们的逆转,基本已经接近了我们的输入,那么几乎可以确定可以逆转回去了。也可以确定对序列号的操作就是base64解码的操作,因为我们是从字节数组编码到字符串,而注册机是从明文字符串解码为字节数组。

经过这次转换,程序对序列号的加密已经拿捏了。
可以推断:
通过正确的加密的序列号字节数组,就能转到原本的序列号上。

我们将用户名为"helloworld"的密码数组求出来。

再代入转换一下:

图片描述

终于成功了。此时,再回头看这个加密函数。一开始不懂的地方也渐渐豁然开朗。

图片描述

平时我们用的base64字符串,涉及到需要补位的时候,都是用的'=',而这个程序,应该是用的"*”吧。

所以每次都会判断输入的字符是不是0x2A,来判断长度之类的。完善下上面的程序,我们就设定第21个字符为 0x2A 即可

再看一下,发现ecx的值随着循环的进行,也慢慢变大,也就是ecx代表大循环。eax代表小循环。

大概类似于这样吧。
虽然求出来了结果,但是仍有一些地方不太理解。不过本就是逆向关键算法,也就没必要什么都弄懂。
本来就调试得头昏眼花了,就不想再多看了。
大家有兴趣可以带着整体思路来看一下程序的完整流程。

总的代码:

 
 
 
 
 
 
 
 
 
 
 
 
0x29304                 0x2AB           SetWindowTextA
0x29270                 0xC6            DrawTextExA
0x29264                 0xC5            DrawTextA
0x29252                 0x2C6           TabbedTextOutA
0x2923A                 0x18D           GetWindowTextLengthA
0x29228                 0x18C           GetWindowTextA
0x29632                 0x29F           TextOutA
0x296A4                 0x258           ScaleViewportExtEx
0x29690                 0x28F           SetViewportExtEx
0x295CE                 0x28D           SetTextColor
0x2963E                 0x122           ExtTextOutA
0x29304                 0x2AB           SetWindowTextA
0x29270                 0xC6            DrawTextExA
0x29264                 0xC5            DrawTextA
0x29252                 0x2C6           TabbedTextOutA
0x2923A                 0x18D           GetWindowTextLengthA
0x29228                 0x18C           GetWindowTextA
0x29632                 0x29F           TextOutA
0x296A4                 0x258           ScaleViewportExtEx
0x29690                 0x28F           SetViewportExtEx
0x295CE                 0x28D           SetTextColor
0x2963E                 0x122           ExtTextOutA
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
void encrystUsernameFirst(string username)
{
    unsigned char data[0x14];
    memset(data, 0, 0x14);
    int eax = 0;
    int ebp = 0x1339E7E;
    int esp = (int)&data - 0x88;
    int edx = (int)&data;
    int ecx = 0;
    int edi = username.length();
    int* esi = 0;
    ebp = ebp - edx;
    while (ecx<0x10)
    {
        eax = ecx;
        edx = eax%edi;
        esi = (int*)&data[ecx];
        ecx++;
        eax = username[edx];
        edx = (int)esi + ebp;
        eax = eax*edx;
        eax = eax*edi;
        (*esi) = (*esi) + eax;
    }
    for (int i = 0; i<0x14; i++)
    {
        printf("%2X ", data[i]);
        if ((i + 1) % 16 == 0)
        {
            cout << endl;
        }
    }
}
void encrystUsernameFirst(string username)
{
    unsigned char data[0x14];
    memset(data, 0, 0x14);
    int eax = 0;
    int ebp = 0x1339E7E;
    int esp = (int)&data - 0x88;
    int edx = (int)&data;
    int ecx = 0;
    int edi = username.length();
    int* esi = 0;
    ebp = ebp - edx;
    while (ecx<0x10)
    {
        eax = ecx;
        edx = eax%edi;
        esi = (int*)&data[ecx];
        ecx++;
        eax = username[edx];
        edx = (int)esi + ebp;
        eax = eax*edx;
        eax = eax*edi;
        (*esi) = (*esi) + eax;
    }
    for (int i = 0; i<0x14; i++)
    {
        printf("%2X ", data[i]);
        if ((i + 1) % 16 == 0)
        {
            cout << endl;
        }
    }
}
 
 
 
 
 
 
 
 
 
 
 
if(a&&b&&c&&d&&e)
{
    success;
}
else
{
    fail;
}
if(a&&b&&c&&d&&e)
{
    success;
}
else
{
    fail;
}
 
 
 
 
 
 
 
 
 
 
 
 
mov eax,dword ptr ds:[esi+edi]
mov eax,dword ptr ds:[esi+edi]
cmp edx,14
cmp edx,14
 
 
void imul(int& eax, int &ecx, int &edx)
{
    long long tmp = eax;
    tmp = tmp*ecx;
    eax = tmp & 0xffffffff;
    edx = tmp >> 32;
}
void encrystUsernameSecond(unsigned char data[0x14])
{
    unsigned char total[0x92];
    memcpy(total + 0x88, data, 0x14);
    memset(total + 0x30, 0, 0x24);
    memset(total + 0x2c, 0, 0x14);
    int esi = 0;
    int ecx = 0;
    int eax = 0;
    int edx = 0x14;
    int i24 = 0x2995c04;
    unsigned char ediData[0x14] = { 0xD7,0x6D,0xF8,0xE7,0xAE,0xFC,0xF7,0x4D,0x76,0xDF,0x8E,0x7A,0xEF,0xCF,0x74,0xD7,0x6D,0xF8,0xE7,0xAE };//这个只和输入的序列号有关系。
    int* edi = (int*)&ediData;
    int unknowndata = 0x3156c04;
    while (esi<0x14)
    {
        ecx = *(int*)&data[esi];
        eax = 0x66666667;
        imul(eax, ecx, edx);
        edx >>= 2; //sar eax,2
        ecx = edx;
        unsigned int tmp = ecx;
        tmp >>= 31;
        //shr ecx,0x1f
        //__asm {
        //    shr tmp,0x1F
        //}
        ecx = tmp;
        ecx += edx;
        edx = 0x14;     //合并起来,固定为0x14
        printf("ecx = %X\n", ecx);
        memcpy(total + 0x2c + esi, (unsigned char*)&ecx, 4);
        if (esi<edx)
        {
            eax = *(int*)&ediData[esi];
            memcpy(total + 0x40 + esi, (unsigned char*)&eax, 4);
            esi += 4;
        }
        cout << endl;
    }
}
void imul(int& eax, int &ecx, int &edx)
{
    long long tmp = eax;
    tmp = tmp*ecx;
    eax = tmp & 0xffffffff;
    edx = tmp >> 32;
}
void encrystUsernameSecond(unsigned char data[0x14])
{
    unsigned char total[0x92];
    memcpy(total + 0x88, data, 0x14);
    memset(total + 0x30, 0, 0x24);
    memset(total + 0x2c, 0, 0x14);
    int esi = 0;
    int ecx = 0;
    int eax = 0;
    int edx = 0x14;
    int i24 = 0x2995c04;
    unsigned char ediData[0x14] = { 0xD7,0x6D,0xF8,0xE7,0xAE,0xFC,0xF7,0x4D,0x76,0xDF,0x8E,0x7A,0xEF,0xCF,0x74,0xD7,0x6D,0xF8,0xE7,0xAE };//这个只和输入的序列号有关系。
    int* edi = (int*)&ediData;
    int unknowndata = 0x3156c04;
    while (esi<0x14)
    {
        ecx = *(int*)&data[esi];
        eax = 0x66666667;
        imul(eax, ecx, edx);
        edx >>= 2; //sar eax,2
        ecx = edx;
        unsigned int tmp = ecx;
        tmp >>= 31;
        //shr ecx,0x1f
        //__asm {
        //    shr tmp,0x1F
        //}
        ecx = tmp;
        ecx += edx;
        edx = 0x14;     //合并起来,固定为0x14
        printf("ecx = %X\n", ecx);
        memcpy(total + 0x2c + esi, (unsigned char*)&ecx, 4);
        if (esi<edx)
        {
            eax = *(int*)&ediData[esi];
            memcpy(total + 0x40 + esi, (unsigned char*)&eax, 4);
            esi += 4;
        }
        cout << endl;
    }
}
 
 
 
 
 
void test3(unsigned char data[])
{
    int ecx = 0;
    int eax = 0;
    int edx = 0;
    int esi = 0;
    ecx = *(int*)&data[0x2c];
    eax = *(int*)&data[0x50];
    edx = eax + ecx;
    ecx = *(int*)&data[0x48];
    if (edx == ecx)
    {
        edx = *(int*)&data[0x30];
        edx += ecx;
        eax += eax;
        if (edx == eax)
        {
            ecx = *(int*)&data[0x4c];
            eax = *(int*)&data[0x34];
            edx = *(int*)&data[0x40];
            esi = ecx + eax;
            if (esi == edx)
            {
                esi = *(int*)&data[0x38];
                esi += edx;
                ecx += ecx;
                if (esi == ecx)
                {
                    edx = *(int*)&data[0x3c];
                    ecx = *(int*)&data[0x44];
                    ecx += edx;
                    edx = eax + eax * 2;
                    if (ecx == edx)
                    {
                        cout << "success\n";
                        return;
                    }
                }
            }
        }
    }
    cout << "fail1\n";
}
void test3(unsigned char data[])
{
    int ecx = 0;
    int eax = 0;
    int edx = 0;
    int esi = 0;
    ecx = *(int*)&data[0x2c];
    eax = *(int*)&data[0x50];
    edx = eax + ecx;
    ecx = *(int*)&data[0x48];
    if (edx == ecx)
    {
        edx = *(int*)&data[0x30];
        edx += ecx;
        eax += eax;
        if (edx == eax)
        {
            ecx = *(int*)&data[0x4c];
            eax = *(int*)&data[0x34];
            edx = *(int*)&data[0x40];
            esi = ecx + eax;
            if (esi == edx)
            {
                esi = *(int*)&data[0x38];
                esi += edx;
                ecx += ecx;
                if (esi == ecx)
                {
                    edx = *(int*)&data[0x3c];
                    ecx = *(int*)&data[0x44];
                    ecx += edx;
                    edx = eax + eax * 2;
                    if (ecx == edx)
                    {
                        cout << "success\n";
                        return;
                    }
                }
            }
        }
    }
    cout << "fail1\n";
}
void test4(unsigned char data[])
{
    int arr1[5];
    int arr2[5];
    memcpy((unsigned char*)&arr1, data + 0x2c, 0x14);
    memcpy((unsigned char*)&arr2, data + 0x40, 0x14);
    int ecx = 0;
    int eax = 0;
    int edx = 0;
    int esi = 0;
    ecx = arr1[0];
    eax = arr2[4];
    edx = ecx + eax;
    ecx = arr2[2];
    if (edx == ecx)//(a[0] + b[4] == b[2])
    {
        edx = arr1[1];
        edx += ecx;
        eax += eax;
        if (edx == eax)//(a[1] + b[2] == 2*b[4])
        {
            ecx = arr2[3];
            eax = arr1[2];
            edx = arr2[0];
            esi = ecx + eax;
            if (esi == edx)//(a[2] + b[3] == b[0])
            {
                esi = arr1[3];
                esi += edx;
                ecx += ecx;
                if (esi == ecx)//(a[3] + b[0] == 2*b[3])
                {
                    edx = arr1[4];
                    ecx = arr2[1];
                    ecx += edx;
                    edx = eax + eax * 2;
                    if (ecx == edx) // (a[4] + b[1] == 3*a[2])
                    {
                        cout << "success\n";
                        return;
                    }
                }
            }
        }
    }
    cout<<"fail\n";
}
void test4(unsigned char data[])
{
    int arr1[5];
    int arr2[5];
    memcpy((unsigned char*)&arr1, data + 0x2c, 0x14);
    memcpy((unsigned char*)&arr2, data + 0x40, 0x14);
    int ecx = 0;
    int eax = 0;
    int edx = 0;
    int esi = 0;
    ecx = arr1[0];
    eax = arr2[4];
    edx = ecx + eax;
    ecx = arr2[2];
    if (edx == ecx)//(a[0] + b[4] == b[2])
    {
        edx = arr1[1];
        edx += ecx;
        eax += eax;
        if (edx == eax)//(a[1] + b[2] == 2*b[4])
        {
            ecx = arr2[3];
            eax = arr1[2];
            edx = arr2[0];
            esi = ecx + eax;
            if (esi == edx)//(a[2] + b[3] == b[0])
            {
                esi = arr1[3];
                esi += edx;
                ecx += ecx;
                if (esi == ecx)//(a[3] + b[0] == 2*b[3])
                {
                    edx = arr1[4];
                    ecx = arr2[1];
                    ecx += edx;
                    edx = eax + eax * 2;
                    if (ecx == edx) // (a[4] + b[1] == 3*a[2])
                    {
                        cout << "success\n";
                        return;
                    }
                }
            }
        }
    }
    cout<<"fail\n";
}
void test5(unsigned char data[])
{
    int a[5];
    int b[5];
    memcpy((unsigned char*)&a, data + 0x2c, 0x14);
    memcpy((unsigned char*)&b, data + 0x40, 0x14);
    //if (((a[0] + b[4])== b[2]) && ((a[1] + b[2]) == (2 * b[4])) && ((a[2] + b[3]) == b[0]) && ((a[3] + b[0]) == (2 * b[3])) && ((a[4] + b[1]) == (3 * a[2])))
    if((2*a[2]+a[3]==b[0])&&(3*a[2]-a[4]==b[1])&&(2*a[0]+a[1]==b[2])&&(a[2]+a[3]==b[3])&&(a[0]+a[1]==b[4]))
    {
        cout << "success\n";
    }
    else
    {
        cout << "fail\n";
    }
}
void test5(unsigned char data[])
{
    int a[5];
    int b[5];
    memcpy((unsigned char*)&a, data + 0x2c, 0x14);
    memcpy((unsigned char*)&b, data + 0x40, 0x14);
    //if (((a[0] + b[4])== b[2]) && ((a[1] + b[2]) == (2 * b[4])) && ((a[2] + b[3]) == b[0]) && ((a[3] + b[0]) == (2 * b[3])) && ((a[4] + b[1]) == (3 * a[2])))
    if((2*a[2]+a[3]==b[0])&&(3*a[2]-a[4]==b[1])&&(2*a[0]+a[1]==b[2])&&(a[2]+a[3]==b[3])&&(a[0]+a[1]==b[4]))
    {
        cout << "success\n";
    }
    else
    {
        cout << "fail\n";
    }
}
 
 
if (true)
    {
        //if ((2 * a[2] + a[3] == b[0]) && (3 * a[2] - a[4] == b[1]) && (2 * a[0] + a[1] == b[2]) && (a[2] + a[3] == b[3]) && (a[0] + a[1] == b[4]))
        int a[5];
        int b[5];
        memcpy((unsigned char*)&a, total + 0x2c, 0x14);
        memcpy((unsigned char*)&b, total + 0x40, 0x14);
        b[0] = 2 * a[2] + a[3];
        b[1] = 3 * a[2] - a[4];
        b[2] = 2 * a[0] + a[1];
        b[3] = a[2] + a[3];
        b[4] = a[0] + a[1];
        memcpy(total + 0x2c, (unsigned char*)&a, 0x14);
        memcpy(total + 0x40, (unsigned char*)&b, 0x14);
    }
    cout << endl;
    cout << "after 0x40" << endl;
    for (int i = 0; i<0x14; i++)
    {
        printf("%02X,", total[i + 0x40]);
    }
if (true)
    {
        //if ((2 * a[2] + a[3] == b[0]) && (3 * a[2] - a[4] == b[1]) && (2 * a[0] + a[1] == b[2]) && (a[2] + a[3] == b[3]) && (a[0] + a[1] == b[4]))
        int a[5];
        int b[5];
        memcpy((unsigned char*)&a, total + 0x2c, 0x14);
        memcpy((unsigned char*)&b, total + 0x40, 0x14);
        b[0] = 2 * a[2] + a[3];
        b[1] = 3 * a[2] - a[4];
        b[2] = 2 * a[0] + a[1];
        b[3] = a[2] + a[3];
        b[4] = a[0] + a[1];
        memcpy(total + 0x2c, (unsigned char*)&a, 0x14);
        memcpy(total + 0x40, (unsigned char*)&b, 0x14);
    }
    cout << endl;
    cout << "after 0x40" << endl;
    for (int i = 0; i<0x14; i++)
    {
        printf("%02X,", total[i + 0x40]);
    }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-4-24 21:45 被kanxue编辑 ,原因: 上传附件
上传的附件:
收藏
免费 5
支持
分享
最新回复 (3)
雪    币: 2402
活跃值: (6808)
能力值: ( LV7,RANK:102 )
在线值:
发帖
回帖
粉丝
2
应该是想要考察基础算法,BASE64,AES之类的,不了解这些算法,就很吃亏
2022-4-23 19:31
0
雪    币: 1522
活跃值: (2177)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
3
今年初赛决赛都是虚拟机
2022-4-25 20:27
0
雪    币: 3416
活跃值: (2123)
能力值: ( LV4,RANK:55 )
在线值:
发帖
回帖
粉丝
4
没看,就是偶然发现做一做,基础还差远了。
2022-4-25 20:58
0
游客
登录 | 注册 方可回帖
返回
//