吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 10150|回复: 33
收起左侧

[CTF] 从一道ctf题目理解rand()随机函数

  [复制链接]
姚小宝 发表于 2018-9-25 21:25
本帖最后由 yechen123 于 2018-12-16 12:43 编辑

先上传附件
random.rar (2.76 KB, 下载次数: 21)
没有cb的看这里 链接: https://pan.baidu.com/s/19O8WkgqHt7HhsuXTht85Zw 提取码: vsy7

先说一下rand()和srand()函数

一般用法是给srand传给一个种子  种子是系统时间
然后用rand产生随机数
看一下rand和srand的代码

[Asm] 纯文本查看 复制代码
void srand(int seed)
{
holdrand=seed;
}
int rand()
{
holdrand=holdrand*0x000343FD+0x00269EC3;
return(holdrand>>0x10)&0x7FFF;
}

可以看出这只是一个伪随机函数 由于一般传给srand的是系统时间 而用户打开软件的时间不确定 所以可以看成随机
但是如果传给srand的并不是系统时间 而是一个确切的数 那么就有可能 能预测rand给出的值
举例
[Asm] 纯文本查看 复制代码
int main()
{
    srand(1);
    printf("%d\n", rand());
    printf("%d\n", rand());
    printf("%d\n", rand());
    printf("%d\n", rand());
    printf("%d\n", rand());
}

这个得出的结果是 11.png
然后我们自己仿写一个srand函数和rand函数
[Asm] 纯文本查看 复制代码
int main()
{

    int hold = 1;
    hold = hold*0x000343FD+0x00269EC3;

    printf("%d\n", (hold>>0x10)&0x7fff);
    hold = hold*0x000343FD+0x00269EC3;
    printf("%d\n", (hold>>0x10)&0x7fff);
    hold = hold*0x000343FD+0x00269EC3;
    printf("%d\n", (hold>>0x10)&0x7fff);
    hold = hold*0x000343FD+0x00269EC3;
    printf("%d\n", (hold>>0x10)&0x7fff);
    hold = hold*0x000343FD+0x00269EC3;
    printf("%d\n", (hold>>0x10)&0x7fff);
    return 0;
}

结果
22.png
可以看出结果是一样的  

那么就表明 如果我们知道seed的值
那么就能预测rand产生的值

开始解析题目
这是一道64位系统下linux的题目
IDA打开
33.png
可以看到有两个循环
这两个循环中里面有sleep函数
主要是想影响你分析时间

接下来看重点
先输入username和password
在经过五个函数
[Asm] 纯文本查看 复制代码
  sub_4008C1(username);                         // 限制username长度 只能为8或者12
  sub_400901(username);
  sub_4009B2(username);                         // 只能为小写或者_
  sub_400A33(username, passwrod);
  return sub_400C23(username, passwrod);


先分析第一个
[Asm] 纯文本查看 复制代码
__int64 __fastcall sub_4008C1(__int64 username)
{
  int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i <= 100 && *(i + username); ++i )
    ;
  return sub_400866(i);
}

__int64 __fastcall sub_400866(int i)
{
  __int64 result; // rax

  if ( 4 * (i >> 2) != i || 4 * (i >> 4) == i >> 2 || !(i >> 3) || (result = (i >> 4), result) )
  {
    puts("Wrong username or password!!!\n");
    exit(0);
  }
  return result;
}

不断循环  一直循环到username结尾 也就是 i就是username长度
在进入sub_400866 这个函数
这段判断代码可以写一个脚本解密一下
[Asm] 纯文本查看 复制代码
    int result;

    for (int i=0; i<100; ++i)
    {
        if (4 * (i >> 2) != i || 4 * (i >> 4) == i >> 2 || !(i >> 3) || (result = i >> 4, result))
        {
            continue;
        }
        printf("%d\n", i);
    }

44.png
也就是说 username长度只能为8 或者12

再看第二个函数
[Asm] 纯文本查看 复制代码
signed __int64 __fastcall sub_400901(signed int *username)
{
  signed __int64 result; // rax
  __int64 v2; // [rsp+18h] [rbp-18h]
  __int64 v3; // [rsp+20h] [rbp-10h]
  __int64 v4; // [rsp+28h] [rbp-8h]

  v2 = *username;                               // 第一个
  v3 = username[1];
  v4 = username[2];
  if ( v2 - v3 + v4 != 0x70667A78
    || v3 + 2 * (v4 + v2) != 0x22F241C1FLL
    || (result = 0x31CD156AC3A69DC4LL, v3 * v4 != 0x31CD156AC3A69DC4LL) )
  {
    puts("Wrong username or password!!!\n");
    exit(0);
  }
  return result;
}

这里主要是解一个三元一次方程组
解方程组在这里不解释
需要注意的是形参声明是signed int *username
是四个字节的 所以在
v2 = *username;                               // 第一个
  v3 = username[1];
  v4 = username[2];
中 v2是username前面四个字节
v3是中间四个字节
v4是后面四个字节
可以预测 username长度为8
还有一点需要注意 就是linux下大端小端的问题
比如abcd(61626364)
在内存中存储是64636261
最后解出来
v2 = 0x6d737469  换成字母就是 msti  倒序过来就是itsm
v3 = 0x6f726265  orbe  ebro
v4 = 0x72656874 reht  ther
那么username就是 itsmebrother

再看下一个函数
[Asm] 纯文本查看 复制代码
__int64 __fastcall sub_4009B2(__int64 username)
{
  __int64 result; // rax
  int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; ; ++i )
  {
    result = *(i + username);                   // 找一遍字母
    if ( !result )
      break;
    if ( (*(i + username) <= 96 || *(i + username) > 122) && *(i + username) != 95 )
    {
      puts("Wrong username or password!!!\n");
      exit(0);
    }
  }
  return result;
}

这个倒是比较简单
主要是判断输入是不是小写和_

再看下一个
[Asm] 纯文本查看 复制代码
__int64 __fastcall sub_400A33(_DWORD *username, _DWORD *password)
{
  int v2; // ST1C_4
  int v3; // ST20_4
  int v4; // ST24_4
  int v5; // ST28_4
  int v6; // ST2C_4
  __int64 result; // rax
  int i; // [rsp+18h] [rbp-28h]

  for ( i = 0; *(password + i); ++i )
  {
    if ( (*(password + i) <= 96 || *(password + i) > 122)
      && (*(password + i) <= 64 || *(password + i) > 90)
      && (*(password + i) <= 47 || *(password + i) > 57) )// 只能大写 小写 数字
    {
      puts("Wrong username or password!!!\n");
      exit(0);
    }
  }
  srand(username[1] + *username + username[2]);
  v2 = *password;
  if ( v2 - rand() != 0x16F48AF6 )
  {
    puts("Wrong username or password!!!\n");
    exit(0);
  }
  v3 = password[1];
  if ( v3 - rand() != 0x200ADA1C )
  {
    puts("Wrong username or password!!!\n");
    exit(0);
  }
  v4 = password[2];
  if ( v4 - rand() != 0x37774C4 )
  {
    puts("Wrong username or password!!!\n");
    exit(0);
  }
  v5 = password[3];
  if ( v5 - rand() != 0x5FC38E35 )
  {
    puts("Wrong username or password!!!\n");
    exit(0);
  }
  v6 = password[4];
  result = (v6 - rand());
  if ( result != 0xAECBAF5 )
  {
    puts("Wrong username or password!!!\n");
    exit(0);
  }
  return result;
}

第一个循环判断password大小写和数字
然后调用srand函数 seed是username[1] + *username + username[2]

前面已经得知username的值
所以可以预测rand的值

好了  昨晚的问题解决了
这个是linux下的程序  所以在windows下调用rand和linux可能有些不同
直接写代码预测rand产生的值
2333.png

爆了个警告 不理他
直接运行
最后rand产生的值时
0x000000005664AD74
0x00000000283E9D1A
0x000000006EE9F96C
0x00000000036FC1FF
0x00000000665B8A42

可以得到password的值为
6d59386a
48497736
72616e30
63335034
71484537

写脚本解一下
[Asm] 纯文本查看 复制代码
>>> i = "6d59386a4849773672616e306333503471484537"
>>> for q in range(0, len(i), 2):
...     flag += chr(int(i[q:q+2], 16))
...

得到
mY8jHIw6ran0c3P4qHE7

在拼一下 得到的passw3ord为
j8Ym6wIH0nar4P3c7EHq
666.png

random.rar

2.76 KB, 下载次数: 4, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 8威望 +1 吾爱币 +17 热心值 +8 收起 理由
Hmily + 1 + 10 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
yourwit + 1 + 1 大佬
杀猪用牛刀 + 1 + 1 谢谢@Thanks!
lovepanda + 1 + 1 我很赞同!
lihaohua + 1 + 1 我很赞同!
afei26579 + 1 + 1 我很赞同!
xiaolei0517 + 1 + 1 用心讨论,共获提升!
luoluoovo + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 姚小宝 发表于 2018-9-26 17:41
afei26579 发表于 2018-9-26 14:24
知道随机因子可以预测 随机结果,这个是有规律。
而知道随机结果是很难推算出随机因子的吧?
计算机的随 ...

嗯 知道随机结果推测随机因子这个没试过 有时间试一下 计算机产生的确实都输入伪随机数
kikyoulin 发表于 2018-9-28 09:22
本帖最后由 kikyoulin 于 2018-9-28 09:24 编辑

感谢分享,分析的很清爽。
但没看过瘾,还是想看看sub_400C23里面有什么猫腻(sub_400A33里定义的result虽然作为返回值,但却没用到)(我自己下载看吧,不劳烦大佬了)

顺便膜拜下大佬
wangqiustc 发表于 2018-9-25 22:08
 楼主| 姚小宝 发表于 2018-9-25 22:09
wangqiustc 发表于 2018-9-25 22:08
可以可以,做题还是很好玩的

我。。。抱歉。。。不是很懂编辑  所以刚刚打完了好多字。。好像没了
 楼主| 姚小宝 发表于 2018-9-25 22:10
wangqiustc 发表于 2018-9-25 22:08
可以可以,做题还是很好玩的

好了 恢复了
jimo 发表于 2018-9-25 23:02
很好,楼主很用心,
 楼主| 姚小宝 发表于 2018-9-25 23:24

看看就好
头像被屏蔽
飞翔的路灯 发表于 2018-9-26 07:42
提示: 作者被禁止或删除 内容自动屏蔽
zhenglihua 发表于 2018-9-26 08:26
可以,很强势,步骤很清晰,学习了,赞一个
头像被屏蔽
sstm 发表于 2018-9-26 09:12
提示: 作者被禁止或删除 内容自动屏蔽
xiaowanzi52 发表于 2018-9-26 09:14
看到这堆数字,说实话我头疼 ,所以不看了,我睡了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 23:24

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表