伪随机数总结

admin 2025年4月24日20:30:09评论0 views字数 14318阅读47分43秒阅读模式

windows与linux下的随机数机制是不一样的,如果给的是elf文件要求随机序列,需要在linux下编译。

C

一般先设置种子srand(0),然后调用rand,前后两次调用rand生成的随机数不同。

动调获取随机序列

2024geek flower

去除花指令,感觉还是有点恶心,先往下做:

伪随机数总结

尝试提取出前几个随机数0x1b,0x13,0x13,0x41

伪随机数总结

用c跑随机数发现和调试的不太一样

伪随机数总结

往后调试发现伪随机数相关的值和明文异或

伪随机数总结

且加密过程只有一步异或

伪随机数总结

a=[0x3E0x980xEB,
0x260x25,
0x8E0x250xE5,
0x860xC8,
0x3F0x980xC8,
0xDE0x52,
0x440xA00xCB,
0x2B0x2A,
0x3C0xAA0xBE,
0xCB0x88,
0x550x9E0x6D,
0xD90x94,
0x970x1C0x52,
0x310x59,
0xFE0x1A0x1A,
0xE80xD0,
0x3A0x9C0x06,
0x5E0x25,
0x5A0xE40x22,
0xA10xC5]
a1=[0x6D,0xC1,0xA8,0x5D,
0x7C,0xBE,0x50,0xBA,
0xE5,0x88,0x51,0xC7,
0xFB,0xB0,0x18,0x2B,
0xD9,0x94,0x52,0x42,
0x59,0xF5,0xF8,0xA7,
0xE7,0x22,0xAD,0x1F,
0x86,0xF5,0xF9,0x65,
0x26,0x58,0x34,0x9B,
0x45,0x7B,0x86,0xB4,
0x65,0xFD,0x68,0x27,
0x52,0x32,0x81,0x50,0xc4,0xb8]
print(len(a1))
flag=''
for i in range(len(a1)):
    flag+=chr(a[i]^a1[i])
print(flag)

#SYC{Y0u_c@n_3nJoy_yhe_Flow3r_anytime_and_anywhere}

2024CISCN gdb_debug

伪随机数只取高位

伪随机数总结

xor rand->交换下标->xor rand->xor string

按理seed生成的伪随机数会很大,与调试结果不符,这也就是题目要求我们调试的原因。

伪随机数总结

一种思路是输入一个flag,得到密文之后xor得到rand1,rand3和ptr,当然可以一位位提取数据。

看汇编去找把rax作为地址的内存,记住开始位置后直接跳出循环,全部提取,这题神奇的点在双击数组进去看不到密文。

伪随机数总结

而需要在调试时看看寄存器的值找内存

伪随机数总结

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

int main() {
    char v28[38];
    for (int i = 0; i < 1; i++) {
        int a[16] = {00x100000000x200000000x300000000x400000000x500000000x600000000x700000000x800000000x900000000xa00000000xb00000000xc00000000xd00000000xe00000000xf0000000};
        srand(a[i]);
        int v31[38] = {2201846418915620111010123918216152105208222252107174125139214141152087910262157250195233362112392551572311};
        int rand1[38]={217152418919922129190248741012429317143512121651031521591264393194175142587616511737180141227123163100};
        int rand3[38]={222170662529817861314797244367321121517142420723321315051202249429423445601481115615788234};
        char ptr[38]={0x120x0E0x1B0x1E0x110x050x070x010x100x220x060x170x160x080x190x130x040x0F0x020x0D0x250x0C0x030x150x1C0x140x0B0x1A0x180x090x1D0x230x1F0x200x240x0A0x000x21};
        for (int i = 0; i < 38; i++) {
            v31[i] = v31[i] ^ rand3[i];
            //printf("%d ",rand());
            //ptr[i] = i;
        }

        // for (int k = 37; k; --k) {
        // int v18 = rand() % 38;
        // //printf("%d ",v18);
        // int tmp = ptr[k];
        // ptr[k] = ptr[v18];
        // ptr[v18] = tmp;
        // }
        //printf("n");
        for (int i = 0; i <38; i++) {
            v28[ptr[i]] = v31[i];
        }
        for (int i = 0; i < 38; i++) {
            v28[i] = v28[i] ^ rand1[i];
        }
        for (int i = 0; i < 38; i++) {
            printf("%c", v28[i]&0xff);
        }
        printf("n");

    }

    return 0;
}
//flag{�8bace5989660ee38f1fd980a4b4fbcd}

最后一位爆破即可:flag{78bace5989660ee38f1fd980a4b4fbcd}

还有一种是直接用时间戳,注意要在linux下运行

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <vector>
#include <algorithm>
#include <stack>
#include <set>
#include <map>
#include <ctime>
#include <unistd.h>

using namespace std;
typedef long long LL;
typedef long double DD;

int main()
{
    srand(((int)time(0))& 0xF0000000);
    char s2[] = "congratulationstoyoucongratulationstoy";
    unsigned char byte_10A0[] = {
    0xBF0xD70x2E0xDA0xEE0xA80x1A0x100x830x730xAC0xF10x060xBE0xAD0x88
    0x040xD70x120xFE0xB50xE20x610xB70x3D0x070x4A0xE80x960xA20x9D0x4D
    0xBC0x810x8C0xE90x880x780x000x00
};
    char rand1[38];
    unsigned int rand2[38],rand3[38];
    int len = strlen(s2);
    cout << "len:" << len << endl;
    for(int i=0;i<len;i++)
        {
            rand1[i] = rand();
            // cout << (unsigned int)(rand1[i]&0xff) << " ";
        }
    for(int i=len-1;i;--i)
        {
            rand2[i] = rand()%(i+1);
            // cout << (unsigned int)(rand2[i]&0xff) << " ";
        }
    for(int i=0;i<len;i++)
        {
            rand3[i] = rand();
        }

    for(int i=0;i<len;i++)
        {
            s2[i] ^= byte_10A0[i];
        }

    for(int i=0;i<len;i++)
        {
            s2[i] ^= rand3[i];
        }

    int str3[39];
    for(int i=0;i<len;i++)
        {
            str3[i] = i;
        }

    for(int i=len-1;i;--i)
        {
            int temp = str3[i];
            str3[i] = str3[rand2[i]];
            str3[rand2[i]] = temp;
        }

    //s2[i]=str2[str3[i]];
    char str2[39] = {0};
    for(int i=0;i<len;i++)
        {
            str2[str3[i]] = s2[i];
        }
    for(int i=0;i<len;i++)
        {
            str2[i] ^= rand1[i];
        }
    cout << str2;

    return 0//-22 61 13 92
}

个人比赛的时候就用了这种,但是rand2的生成循环写反了,以及rand1和rand3的位置没考虑。

#include <stdio.h>
#include <string.h>
#include <time.h>
#include<stdlib.h>
#include<stdint.h>
int main() {
    char v28[38];
    for(int i=0;i<1;i++){
        //int a[16]={0,0x10000000,0x20000000,0x30000000,0x40000000,0x50000000,0x60000000,0x70000000,0x80000000,0x90000000,0xa0000000,0xb0000000,0xc0000000,0xd0000000,0xe0000000,0xf0000000};
        srand(((int)time(0))&0xf0000000);
        unsigned char v31[38]={2201846418915620111010123918216152105208222252107174125139214141152087910262157250195233362112392551572311};
        char s[50]="congratulationstoyoucongratulationstoy";
        int ptr[38];
        unsigned int rand1[38];
        unsigned int rand2[38];
        unsigned int rand3[38];
        for(int i =0;i<38;i++){
            rand1[i]=rand();
            //printf("%d ",rand1[i]);
        }
        printf("nn");
        for(int i=0;i<37;i++){
            rand2[i]=rand();
            //printf("%d ",rand2[i]);
        }
        printf("nn");
        for(int i =0;i<38;i++){
            rand3[i]=rand();
            //printf("%d ",rand3[i]);
        }
        for(int i=0;i<38;i++){
            v31[i]=v31[i]^rand3[i];
            printf("%d ",rand3[i]);
            ptr[i]=i;
        }

        for(int k=37,j=0;k>=0;k--,j++){
            uint32_t t=rand2[j]%(k+1);
            printf("%d ",t);
            char tmp=ptr[k];
            ptr[k]=ptr[t];
            ptr[t]=tmp;
        }

        for(int i=0;i<38;i++){
            v28[ptr[i]]=v31[i];
        }
        for(int i=0;i<38;i++){
            v28[i]=v28[i]^rand1[i];
        }
        //for(int i=0;i<38;i++){
        // printf("%c",v28[i]&0x7f);
        //}
        printf("%s",v28);
        printf("n");
    }

    return 0;
}

爆破seed

山东省赛的一道题可以参考:0b3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7q4)9J5k6i4N6W2K9i4S2A6L8W2)9J5k6i4q4I4i4K6u0W2j5$3!0E0i4K6u0r3M7#2)9J5c8U0y4b7h3V1D9J5e0K6u0b7k6Y4c8o6M7i4t1J5L8g2x3%4N6X3^5#2N6@1p5`.

2023春秋杯冬季赛

upx2023_0.zip

不让直接脱,也不是特征码的问题,那大概率就是手动脱壳

伪随机数总结

看上去像是程序入口,但实际不是

伪随机数总结

直接搜jmp

伪随机数总结

这样就算是脱壳完毕了,用syclla插件导出即可

伪随机数总结

伪随机数总结

看了wp,原来upx要小写改大写

伪随机数总结

然后脱壳,c++更明显

伪随机数总结

伪随机数总结

双击v7按几次d就发现只是顺序变了

伪随机数总结

找到修改时间往前爆

伪随机数总结

#include <stdio.h>
#include <stdlib.h>

int main() {
    int seed, i, key;
    for (seed = 1685762995; seed > 0; seed--) {
        srand(seed);
        int right = 1;
        for (i = 0; i <= 32; i++) {
            key = rand() % 255;
            switch (i) {
                case 0:
                    if (key != ('f' ^ 0x09)) { //102^9=111(0x6F)
                        right = 0;
                    }
                    break;
                case 1:
                    if (key != ('{' ^ 0x63)) { //123^99=24(0x18)
                        right = 0;
                    }
                    break;

                case 11:
                    if (key != ('l' ^ 0xC6)) { //108^198=170(0xAA)
                        right = 0;
                    }
                    break;
                case 12:
                    if (key != ('g' ^ 0x65)) { //103^101=2(0x02)
                        right = 0;
                    }
                    break;
                case 32:
                    if (key != ('a' ^ 0xFA)) { //97^250=155(0x9B)
                        right = 0;
                    }
                    break;
                default:
                    break;
            }
            if (right == 0) {
                break;
            }
        }
        if (right == 1) {
            printf("%un", seed);
            break;
        }
    }
    int data[] = { 0x090x630xD9,
                  0xF60x58,
                  0xDD0x3F0x4C,
                  0x0F0x0B,
                  0x980xC60x65,
                  0x210x41,
                  0xED0xC40x0B,
                  0x3A0x7B,
                  0xE50x750x5D,
                  0xA90x31,
                  0x410xD70x52,
                  0x6C0x0A,
                  0xFA0xFD0xFA,
                  0x840xDB,
                  0x890xCD0x7E,
                  0x270x85,
                  0x130x08
                  };
    srand(seed);
    for (int i = 0; i < 42; i++)
        printf("%c", ((rand() % 255) ^ data[i]) & 0xff);
}
//1682145110
//f{52bgb-281lg00ff-46f7-ca009c8e}a381-b7191

再通过python索引把位置换回来

example='flag{1234567890zxcvbnmlkjhgfdsaqwertyuiop}'
result='f{48xnjdwyplg13579zcbmkhfsqetuo}a260vlgari'
crypto = "f{52bgb-281lg00ff-46f7-ca009c8e}a381-b7191"

for i in example:
    print(crypto[result.index(i)], end="")

#flag{0305f8f2-14b6-fg7l-bcgf-0a0299c881e1}

Python

48cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6D9j5i4A6*7P5X3q4J5L8#2)9J5k6h3N6A6N6r3S2#2j5W2)9J5k6h3W2G2i4K6u0r3x3U0l9J5x3q4)9J5c8U0p5I4i4K6u0r3x3o6N6Q4x3V1k6U0M7Y4W2H3N6r3!0Q4x3X3c8Q4x3U0g2q4y4W2)9J5y4f1t1#2i4K6t1#2z5o6q4Q4x3U0g2q4y4g2)9J5y4f1q4r3i4K6t1#2z5o6k6Q4x3U0g2q4y4#2)9J5y4f1p5H3i4K6t1#2z5o6q4Q4x3V1j5`.

python中random库使用的是MT19937算法(梅森旋转算法),利用算法可以求出后随机数,前未知随机数,种子等,详见博客

1.利用seed初始化624个状态

2.对状态进行旋转

3.根据状态提取伪随机数

def _int32(x):
    return int(0xFFFFFFFF & x)

class MT19937:
    # 根据seed初始化624的state
    def __init__(self, seed):
        self.mt = [0] * 624
        self.mt[0] = seed
        self.mti = 0
        for i in range(1624):
            self.mt[i] = _int32(1812433253 * (self.mt[i - 1] ^ self.mt[i - 1] >> 30) + i)

    # 提取伪随机数
    def extract_number(self):
        if self.mti == 0:
            self.twist()
        y = self.mt[self.mti]
        y = y ^ y >> 11
        y = y ^ y << 7 & 2636928640
        y = y ^ y << 15 & 4022730752
        y = y ^ y >> 18
        self.mti = (self.mti + 1) % 624
        return _int32(y)

    # 对状态进行旋转
    def twist(self):
        for i in range(0624):
            y = _int32((self.mt[i] & 0x80000000) + (self.mt[(i + 1) % 624] & 0x7fffffff))
            self.mt[i] = (y >> 1) ^ self.mt[(i + 397) % 624]

            if y % 2 != 0:
                self.mt[i] = self.mt[i] ^ 0x9908b0df

有默认种子,由当前时间和操作系统提供的熵源例如urandom综合生成

import random
import time

print(int(time.time()))
print('随机数1:',random.random())
print(int(time.time()))
random.seed(int(time.time()))
print('随机数2:',random.random())
random.seed(0)
print('随机数3:',random.random())

# 1732158156
# 随机数1: 0.4747416427572331
# 1732158156
# 随机数2: 0.2260060177159785
# 随机数3: 0.8444218515250481

[GKCTF 2021]Random

如果能获取前624个32位的随机数,就能预测出后面全部32位的随机数

import random
from hashlib import md5
 
def get_mask():
    file = open("random.txt","w")
    for i in range(104):
        file.write(str(random.getrandbits(32))+"n")
        file.write(str(random.getrandbits(64))+"n")
        file.write(str(random.getrandbits(96))+"n")
    file.close()
get_mask()
flag = md5(str(random.getrandbits(32)).encode()).hexdigest()
print(flag)

random的随机数以32位为一个单位,所以如果要产生一个64位的随机数,则等价于一次产生两个32位随机数。

本题中已知的随机数有104*(1+2+3)=624个,刚好满足能够预测的条件,需要预测出下一个。

randcrack

from hashlib import md5
from randcrack import RandCrack

with open(r'random.txt''r'as f:
    l = f.readlines()
l = [int(i.strip()) for i in l]
t = []
for i in range(len(l)):
    if i % 3 == 0:
        t.append(l[i])  # 32位长度直接存入
    elif i % 3 == 1:
        t.append(l[i] & (2 ** 32 - 1))  # 64位长度先存入低32位
        t.append(l[i] >> 32)  # 再存入高32位
    else:
        t.append(l[i] & (2 ** 32 - 1))
        t.append(l[i] & (2 ** 64 - 1) >> 32)
        t.append(l[i] >> 64)
rc = RandCrack()
for i in t:
    rc.submit(i)  # 把每个数据都丢进预测器里
flag = rc.predict_getrandbits(32)  # 预测的下一个32位
print(md5(str(flag).encode()).hexdigest())

列举全部state的状态

from random import Random

def invert_right(m,l,val=''):
    length = 32
    mx = 0xffffffff
    if val == '':
        val = mx
    i,res = 0,0
    while i*l<length:
        mask = (mx<<(length-l)&mx)>>i*l
        tmp = m & mask
        m = m^tmp>>l&val
        res += tmp
        i += 1
    return res

def invert_left(m,l,val):
    length = 32
    mx = 0xffffffff
    i,res = 0,0
    while i*l < length:
        mask = (mx>>(length-l)&mx)<<i*l
        tmp = m & mask
        m ^= tmp<<l&val
        res |= tmp
        i += 1
    return res

def invert_temper(m):
    m = invert_right(m,18)
    m = invert_left(m,15,4022730752)
    m = invert_left(m,7,2636928640)
    m = invert_right(m,11)
    return m

def clone_mt(record):
    state = [invert_temper(i) for i in record]
    gen = Random()
    gen.setstate((3,tuple(state+[0]),None))
    return gen


f = open("random.txt",'r').readlines()
prng = []
j=0
for i in f:
    i = i.strip('n')
    print(int(i).bit_length())
    if(j%3==0):
        prng.append(int(i))
    elif(j%3==1):#将生成两次随机数的两个随机数分离出来
        prng.append(int(i)& (2 ** 32 - 1))
        prng.append(int(i)>> 32)
    else:#将生成三次随机数的三个随机数分离出来
        prng.append(int(i)& (2 ** 32 - 1))
        prng.append(int(i)& (2 ** 64 - 1) >> 32)
        prng.append(int(i)>>64)
    j+=1

g = clone_mt(prng[:624])
for i in range(624):
    g.getrandbits(32)#产生前624个随机数,让state状态到生成flag前

key = g.getrandbits(32)
print(key)
from hashlib import md5
flag = md5(str(key).encode()).hexdigest()
print(flag)
#14c71fec812b754b2061a35a4f6d8421

2023HITCTF邀请赛

数据:output.zip

import random

with open('output.bin''wb'as f:
    f.write(random.randbytes(2500))

print('HITCTF2023{%s}' % random.randbytes(16).hex())

题目已知产生了2500个byte,一个byte是8位,也就是说4个byte组成一个32位随机数,2500/4=625>624,满足预测条件。

import random
from mt19937predictor import MT19937Predictor

#读取数据,并4个一组组成一个32位随机数(little是重点)
c = open('output.bin''rb').read()
c = [c[x:x+4for x in range(0len(c), 4)]
c = [int.from_bytes(x, 'little'for x in c]

predictor = MT19937Predictor()
for x in c[:624]:
predictor.setrandbits(x, 32#只需要624组数据就行
assert predictor.getrandbits(32) == c[-1]
print('HITCTF2023{%s}' % predictor.randbytes(16).hex())
# HITCTF2023{d6712c20657ce5e02118f8592b7da71f}

伪随机数总结

看雪ID:j1ya

https://bbs.kanxue.com/user-home-973236.htm

*本文为看雪论坛优秀文章,由 j1ya 原创,转载请注明来自看雪社区

原文始发于微信公众号(看雪学苑):伪随机数总结

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月24日20:30:09
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   伪随机数总结https://cn-sec.com/archives/3996181.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息