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的分享