SimpleXor WriteUp

自己写的题,直接上ida

等ida初始化完毕后,直接shift+F12查找字符串

我们快速定位到关键位置

直接搜flag:

这里ida没有显示全是正常现象,需要更改设置,这里不再赘述

双击它

然后

我们选中它然后按下X键,交叉引用

点ok

好吧,原来就在main里。

F2下断点

点这个三角开始调试

Ida有个生成伪代码的功能,非常强大,快捷键为F5,但我不推荐依赖这个功能。因为当有一天你不能F5的时候你看汇编会一脸懵逼

步过当前RIP指向的这个call的时候,阻塞住了,这就是要我们输入字符串,我们可以选中这个call后面的标签sub_xxxxx然后按下N键给它重命名,为了防止命名重复,推荐_scanf或_cin 加个下划线

输入随手捏造的flag: qsnctf{123456789}

然后继续往下走

这里我们可以看到,rcx为flag的前缀,自增rdx,然后rdx作为一个偏移,读取rcx+rdx里的数据,跟R8做判断,此时r8为0

这就是典型的计算字符串长度 strlen()

此处rcx的值为flag前缀这串字符的地址

Movzx eax, byte ptr[rcx] 把flag的字符串里的一个字符给了eax

然后跟r9+rcx里的数据比较,r9+rcx的地址正好是我们输入的字符串

所以可以推断这是个判断flag前缀的操作

看到这个地址一点一点自增就更加确信了

这个无论怎么看都是判断flag格式结尾,判断输入进来的字符串结尾是否为’}’

好啊,又是个取字符串长度

这里我们需要注意一下,这个跟常数做判断,极大可能是判断flag长度,我们需要小心,我们双击jnz后面这个loc_xxxxx

发现

再双击进去看

Ok,看来还真是,esc键返回去,把那个标签直接重命名

我们也把那个call给重命名一下

然后发现下面call也变了

顺手把下面那个也给重命名了

Ok

下个断点,重新调试,重新编造flag,注意,这个长度是除去格式的长度(因为: 如果同样的算法,连flag的前缀都加密,那么你输入进来的数据进行加密后,前几个字节是与正确值是一样的,那么很容易在内存中找到加密后的正确flag, 而且这个去掉flag前后缀的操作就在前面)

长度是0x1A(26)

qsnctf{0123456776543210ABCDEFGHIG}

然后重新调试

看到这种位移或者异或,请留意,因为很可能是算法

一直往下走,会有个跳转

会跳回来

这里很绕我们可以F5(不要依赖这个东西)看看

仔细看, 0x51 >> i 这个结果我们无需关心,因为后面有个&1

假设0x51 >> i的结果为x, x&1的结果也只有1个二进制位, 不是0就是1, 看起来非常非常乱,非常绕,但当你仔细看的时候,你会觉得并没有那么乱。与运算就是两个操作数的对应的二进制位都是1则为1反之为0, 所以:

假设i为0 那么0x51 >> 0等于0x51

0101 0001 = 0x51

0000 0001 = 1

这样一来,只会保留一个二进制位,所以结果非0即1

无需担心,而且,这个操作,就等于取除以2的余数

接着看下一行

这不是我们输入进来的值吗?

我们输入进来的值位移也进行了一个取最后一位的操作

判断是否不等于0

如果我们输入的数据的当前字符的最后一个二进制位是1

则进入if, 继续判断currentBit,也就是0x51的最后一个二进制位是否为1,为1则continue,只有i++, 当前的我们输入的字符串的指针并不发生改变,反之如果我们当前字符的最后一个二进制位为0,则进入else if,判断0x51的最后一个二进制位如果为0则直接continue

整个for循环都是同一个字符进行循环并没有改变字符串指针

我们再看v16,是外面的一个值,v16 = v16 | (1 << i)

这句代码的本质是设置二进制位,因为将1左移n位,进行一个或运算,只要两个操作数的对应的二进制位有一个是1

则结果对应的二进制位就为1

我们也不难发现这个循环就是一直在操作二进制位

我们理解一下整体逻辑,发现整体逻辑就是取0x51的对应二进制位,i作为index, 取第几位就往右移动几位。

然后判断当前数据的二进制位和0x51的二进制位是否都是1

都是1则continue,v16的那一位并没有发生改变。

反之要都是0则直接continue,也不改变v16的当前位的值

所以整体理解下来,就是两个操作数为1则为0, 两个操作数都为0则为0 两个操作数一个为1一个为0则v16对应的二进制位置1

看到这里,我们就可以知道这个算法,其实就是xor

Xor的逻辑如下:

0000 1101 = 0xD

xor

0000 0011 = 0x3

0000 1110 = 0xE

也就是同样为0则为0,同样为1则为0,有一个操作数对应的位有1另一个为0则为1

这就是异或运算

继续往下看

这有个while循环,也就是把每个字符都与0x51进行异或

然后再进行写入

比较内存,拿我们加密后的数据跟正确flag加密后的数据进行比较

Memcmp最后一个参数为大小,0x1A也就是26

我们

然后num键+*键

然后shift+E

可以直接复制走,但如果数据太多则建议点击export进行导出

好了,到这一步,我们就可以打开VS来解密了

 

好了,到这里就完成了

这个题主要考验的是对位运算的理解和运用。

题目源码下载地址

链接:https://pan.baidu.com/s/1hZeIN8VcfP_EvrUmAmlG8g?pwd=txdh
提取码:txdh
--来自百度网盘超级会员V3的分享

posted @ 2023-01-09 23:21  N0t3  阅读(45)  评论(0编辑  收藏  举报