EzRand
和seed爆了!
文件{:download="ez_rand.exe"}
扔进IDA里分析,发现是一个简单的异或运算比较
if (加密的flag[i] != 加密后的输入[i]) 退出程序
但是这里的加密算法比较奇怪,是“随机的”
srand(time(NULL)); // 设置随机种子
for (...) {
v = rand();
加密后的输入 = 函数(v)
}
经过李师傅的提醒
.text:00007FF763EA1189 xor ecx, ecx ; Time
.text:00007FF763EA118B mov [rsp+70h+arg_0], rsi
.text:00007FF763EA1193 call cs:_time64 ; Indirect Call Near Procedure
.text:00007FF763EA1199 movzx ecx, ax ; Seed
.text:00007FF763EA119C call cs:srand ; Indirect Call Near Procedure
这里的 ax 是个16位寄存器,即范围是 0~FFFF
以及这里是个
movzx
,可以将源操作数的内容拷贝到目的操作数,并将该值0扩展至16位或者32位
所以完全可以爆破 srand
- 对于前8个通用寄存器,即eax, ebx, ecx, edx, esi, edi, esp和ebp
不同的前缀用于区分寄存器的位数(64, 32或16)。
64位寄存器以r前缀, 32位则以e为前缀,16位则无前缀。
例如,ax的64位寄存器是rax,32位寄存器是eax,16位则是ax。
不同的后缀用于区分寄存器低16位中的高8位和低8位。
高8位以h为后缀,低8位以l为后缀。例如, ax的高8位是ah, 低8位是al
- 对于r8至r15的寄存器,无后缀表示64位,32位以d为后缀,16位以w为后缀,8位以b为后缀。
例如, r15表示64位,r15d表示32位,r15w表示16位,r16b表示8位。
有一点需要注意,r8至r15不像前8个通用寄存器是没有低16位中高8位的表示法的。
需要注意的点#
正确的编译工具#
同样的代码,不同编译工具下的程序运行结果可能完全不同,特别是像 rand()
这里使用的是 MSVC 19.35 工具链,使用 VS。
最后的代码#
其实大部分是从IDA F5复制过来的
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main()
{
int v9[7];
v9[0] = -362017699;
v9[1] = 888936774;
v9[2] = 119759538;
v9[3] = -76668318;
v9[4] = -1443698508;
v9[5] = -2044652911;
v9[6] = 1139379931;
char* cv9 = (char*)v9;
char result[31];
for (int seed = 0; seed <= 0xFFFF; seed++)
{
srand(seed);
for (int i = 0; i < 30; i++)
{
int v7 = rand();
unsigned __int8 num = (unsigned __int8)(v7
+ ((((unsigned __int64)(2155905153i64 * v7) >> 32) & 0x80000000) != 0i64)
+ ((int)((unsigned __int64)(2155905153i64 * v7) >> 32) >> 7));
result[i] = cv9[i] ^ num;
}
if (strstr(result, "XYCTF"))
{
printf("%X-%s\n", seed, result);
}
}
}
小知识#
2024-04-11更新
这里的一大坨运算代码
(unsigned __int8)(v7
+ ((((unsigned __int64)(2155905153i64 * v7) >> 32) & 0x80000000) != 0i64)
+ ((int)((unsigned __int64)(2155905153i64 * v7) >> 32) >> 7))
其实是MSVC编译器对 % 255
优化后的结果
汇编代码为:
.text:00007FF763EA11B9 mov eax, 80808081h
.text:00007FF763EA11BE imul r8d ; Signed Multiply
.text:00007FF763EA11C1 add edx, r8d ; Add
.text:00007FF763EA11C4 sar edx, 7 ; Shift Arithmetic Right
.text:00007FF763EA11C7 mov ecx, edx
.text:00007FF763EA11C9 shr ecx, 1Fh ; Shift Logical Right
.text:00007FF763EA11CC add edx, ecx ; Add
.text:00007FF763EA11CE imul ecx, edx, 0FFh ; Signed Multiply
.text:00007FF763EA11D4 sub r8d, ecx ; Integer Subtraction
.text:00007FF763EA11D7 xor r8b, byte ptr [rbp+rsi+var_30] ; Logical Exclusive OR
使用 CompilerExplorer 对比
#include <stdio.h>
int main() {
int b = 0;
scanf("%d", &b);
int a = b % 255;
printf("%d", a);
}
编译器选择 x64 msvc v19.35
,编译优化选择 /Ox
或以上(默认 /Od
不会有优化)
mov ecx, DWORD PTR b$[rsp]
mov eax, -2139062143 ; ffffffff80808081H
imul ecx
add edx, ecx
sar edx, 7
mov eax, edx
shr eax, 31
add edx, eax
imul eax, edx, 255 ; 000000ffH
sub ecx, eax
一毛一样