32位汇编语言学习笔记(43)-- 生成随机数



此程序出自《Assembly Language step by step programming with linux》第12章,用于演示随机数函数的使用,共涉及两个随机数函数:
void srand( unsigned int seed ); //设置随机数种子
int rand( void ); //获取随机数

先看程序:

[SECTION .data]			; Section containing initialised data

Pulls	   dd 36		;  How many numbers do we pull?
Display    db 10,'Here is an array of %d %d-bit random numbners:',10,0
ShowArray  db '%10d %10d %10d %10d %10d %10d',10,0		
CharTbl db '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-@'

[SECTION .bss]		; Section containing uninitialized data

BUFSIZE  equ 70		; # of randomly chosen chars
RandVal  resd 1		; Reserve an integer variable
Stash    resd 72	; Reserve an array of 72 integers for randoms
RandChar resb BUFSIZE+5	; Buffer for storing randomly chosen characters

[SECTION .text]		; Section containing code

extern printf	
extern puts
extern rand
extern scanf	
extern srand
extern time			
		
pull31: mov ecx,0		; For 31 bit random, we don't shift
	jmp pull
pull16: mov ecx,15		; For 16 bit random, shift by 15 bits
	jmp pull
pull8:	mov ecx,23		; For 8 bit random, shift by 23 bits
	jmp pull
pull7:  mov ecx,24		; For 7 bit random, shift by 24 bits
	jmp pull
pull6:	mov ecx,25		; For 6 bit random, shift by 25 bits
	jmp pull
pull4:	mov ecx,27		; For 4 bit random, shift by 27 bits
pull:	push ecx		; rand trashes ecx; save shift value on stack
	call rand		; Call rand for random value; returned in EAX
	pop ecx			; Pop stashed shift value back into ECX
	shr eax,cl		; Shift the random value by the chosen factor
				;  keeping in mind that part we want is in CL
	ret			; Go home with random number in EAX

newline:
	mov ecx,10	; We need a skip value, which is 10 minus the
	sub ecx,eax	;  number of newlines the caller wants.
	add ecx,nl	; This skip value is added to the address of
	push ecx	;  the newline buffer nl before calling printf.
	call printf	; Display the selected number of newlines
	add esp,4	; Stack cleanup for one parm
	ret		; Go home
nl	db 10,10,10,10,10,10,10,10,10,10,0
	
shownums:	
	mov esi, dword [Pulls]	; Put pull count into ESI
.dorow:	mov edi,6		; Put row element counter into EDI
.pushr:	dec edi			; Decrement row element counter
	dec esi			; Decrement pulls counter
	push dword [Stash+esi*4]; Push number from array onto stack
	cmp edi,0		; Have we filled the row yet?
	jne .pushr		; If not, go push another one
	push ShowArray		; Push address of base display string
	call printf		; Display the random numbers
	add esp,28		; Stack cleanup: 7 items X 4 bytes = 28
	cmp esi,0		; See if pull count has gone to 0
	jnz .dorow		; If not, we go back and do another row!
	ret			; Done, so go home!
	
puller:
	mov esi,dword [Pulls]	; Put pull count into ESI
.grab:	dec esi			; Decrement counter in ESI
	call edi		; Pull the value; it's returned in eax
	mov [Stash+esi*4],eax   ; Store random value in the array
	cmp esi,0		; See if we've pulled 4 yet
	jne .grab		; Do another if ESI <> 0 
	ret			; Otherwise, go home!
	
%macro GenAndShowNBitRandom 2  
    mov edi, %1	; Copy address of random # subroutine into edi
	call puller	; Pull as many numbers as called for in [pulls]				
	push %2		; Size of numbers being pulled, in bits
	push dword [Pulls] ; Number of random numbers generated
	push Display	; Address of base display string
	call printf	; Display the label
	add esp,12	; Stack cleanup: 3 parms X 4 bytes = 12
	call shownums	; Display the rows of random numbers
%endmacro  

; MAIN PROGRAM:
					
global main			; Required so linker can find entry point
	
main:
    push ebp		; Set up stack frame for debugger
	mov ebp,esp
	push ebx		; Program must preserve EBP, EBX, ESI, & EDI
	push esi
	push edi
;;; Everything before this is boilerplate; use it for all ordinary apps!	

; Begin by seeding the random number generator with a time_t value:	
Seedit:	push 0		; Push a 32-bit null pointer to stack
	call time	; Returns time_t value (32-bit integer) in EAX
	add esp,4	; Stack cleanup for one parm
	push eax	; Push time_t value in EAX onto stack
	call srand	; Time_t value is the seed value for random # gen
	add esp,4	; Stack cleanup for one parm

; All of the following code blocks are identical except for the size of
; the random value being generated:
	
; Create and display an array of 31-bit random values
    GenAndShowNBitRandom pull31,32
	
; Create and display an array of 16-bit random values
    GenAndShowNBitRandom pull16,16
	
; Create and display an array of 8-bit random values:
    GenAndShowNBitRandom pull8,8

; Create and display an array of 7-bit random values:
    GenAndShowNBitRandom pull7,7

; Create and display an array of 4-bit random values:
    GenAndShowNBitRandom pull4,4

; Clear a buffer to nulls:
Bufclr:	mov ecx, BUFSIZE+5  ; Fill whole buffer plus 5 for safety
.loop:	dec ecx		    ; BUFSIZE is 1-based so decrement first!
	mov byte [RandChar+ecx],0     ; Mov null into the buffer
	cmp ecx,0	    ; Are we done yet?
	jnz .loop	    ; If not, go back and stuff another null

; Create a string of random alphanumeric characters:
Pulchr:	mov ebx, BUFSIZE	; BUFSIZE tells us how many chars to pull
.loop:	dec ebx			; BUFSIZE is 1-based, so decrement first!
	mov edi,pull6		; For random in the range 0-63
	call puller		; Go get a random number from 0-63
	mov cl,[CharTbl+eax]	; Use random # in eax as offset into table
	                        ;  and copy character from table into CL
	mov [RandChar+ebx],cl	; Copy char from CL to character buffer
	cmp ebx,0		; Are we done having fun yet?
	jne .loop		; If not, go back and pull another

; Display the string of random characters:
	mov eax,1	; Output a newline
	call newline	;  using the newline procedure
	push RandChar	; Push the address of the char buffer 
	call puts	; Call puts to display it
	add esp,4	; Stack cleanup for one parm
	mov eax,1	; Output a newline
	call newline	;  using the newline subroutine
		
;;; Everything after this is boilerplate; use it for all ordinary apps!
	pop edi		; Restore saved registers
	pop esi
	pop ebx
	mov esp,ebp	; Destroy stack frame before returning
	pop ebp
	ret		; Return control to Linux


程序分析:
pull函数,这个函数有些奇怪,有很多入口,主要用于设置ecx值,最终会跳转到pull。ecx用于控制右移的位数。函数最终目的是生成有位数限制的随机数。
pull31: mov ecx,0  //随机数是31位,不右移
 jmp pull
pull16: mov ecx,15  //16位随机数,右移15位
 jmp pull
pull8: mov ecx,23  //8位随机数,右移23位
 jmp pull
pull7:  mov ecx,24  //7位随机数,右移24位
 jmp pull
pull6: mov ecx,25  //6位随机数,右移25位
 jmp pull
pull4: mov ecx,27  //4位随机数,右移27位
pull: push ecx  //保存ecx值
 call rand  //调用rand函数,生成伪随机数
 pop ecx     //恢复ecx值
 shr eax,cl  //返回的随机数值右移cl位
 ret   

newline函数,用于打印0-10个空行,空行个数由eax来控制。
newline:
 mov ecx,10 //ecx=10
 sub ecx,eax //ecx = ecx -eax
 add ecx,nl //ecx=nl+ecx,nl是一个字节数组的首地址,保存10个换行符
 push ecx //保存格式化字符串作为入参
 call printf //调用printf函数 
 add esp,4  //清理调用栈
 ret  
nl db 10,10,10,10,10,10,10,10,10,10,0

shownums函数用于打印Stash数组中的随机数。
shownums: 
 mov esi, dword [Pulls] //esi=36
.dorow: mov edi,6  //edi=6
.pushr: dec edi   //edi=edi-1
 dec esi   //esi = esi -1
 push dword [Stash+esi*4]//把数组元素压入栈,用于作为printf的入参
 cmp edi,0  //edi和0比较
 jne .pushr  //如果不等于0,跳转到.pushr
 push ShowArray  //格式化字符串压入栈
 call printf  //调用printf显示随机数
 add esp,28  //清理栈(7个参数)
 cmp esi,0  比较esi和0
 jnz .dorow  //如果不等于0,跳转到.dorow,显示接下来六个随机数
 ret   

puller用于生成随机数,并把结果保存到Stash数组中
puller:
 mov esi,dword [Pulls] //esi = 36
.grab: dec esi   //esi = esi -1
 call edi  //此时edi应该装载的是pull函数的几个入口地址之一,call edi会调用pull函数
 mov [Stash+esi*4],eax   //保存随机数到Stash[4*esi]数组中
 cmp esi,0  //比较esi和0
 jne .grab     //如果esi不等于0, 跳转,继续循环。
 ret   

GenAndShowNBitRandom宏,用于生成规定位数的随机数,并打印出显示信息,宏的第一个参数是pull函数的跳转地址,第二个参数是随机数的位数。
%macro GenAndShowNBitRandom 2 
    mov edi, %1 //edi=pull函数跳转地址,例如pull31
 call puller //调用puller函数,生成随机数
 push %2  //printf函数的最右一个参数:随机数的位数
 push dword [Pulls]  //随机数个数
 push Display //格式化字符串地址
 call printf //调用printf函数,打印随机数概要信息
 add esp,12 //清理栈,3个参数
 call shownums //打印随机数信息。
%endmacro 

主程序:
Seedit: push 0  //timer=0
 call time //调用time函数,获取当前时间
 add esp,4  //清理栈
 push eax  //time_t值作为srand函数入参
 call srand  //调用srand函数,设置随机数种子
 add esp,4  //清理栈

    GenAndShowNBitRandom pull31,32  //生成并打印32位随机数
    GenAndShowNBitRandom pull16,16 //生成并打印16位随机数
    GenAndShowNBitRandom pull8,8 //生成并打印8位随机数
    GenAndShowNBitRandom pull7,7 //生成并打印7位随机数
    GenAndShowNBitRandom pull4,4  //生成并打印4位随机数

Bufclr: mov ecx, BUFSIZE+5  //ecx= BUFSIZE+5
.loop: dec ecx      //ecx=ecx-1
 mov byte [RandChar+ecx],0     // RandChar[ecx]=0
 cmp ecx,0     //比较ecx和0
 jnz .loop     //如果ecx不等于0,继续循环

Pulchr: mov ebx, BUFSIZE //ebx= BUFSIZE
.loop: dec ebx   //ebx= BUFSIZE-1
 mov edi,pull6  //edi=pull6,用于生成六位随机数
 call puller  //调用puller函数,生成六位随机数(0-63)
 mov cl,[CharTbl+eax] //cl = CharTbl[eax],使用随机数作为索引获取字母表中的字母,保存到cl中。
 mov [RandChar+ebx],cl // RandChar[ebx]=cl
 cmp ebx,0 //ebx和0比较
 jne .loop  //不等于0继续循环,共循环BUFSIZE次。

 mov eax,1 //eax=1,要求打印一个换行符
 call newline //调用newline函数,打印一个换行符
 push RandChar //需要打印的RandChar字符串
 call puts //调用puts函数进行打印
 add esp,4  //清理栈
 mov eax,1 //eax=1,要求打印一个换行符
 call newline //调用newline函数,打印一个换行符

makefile文件内容:

randtest: randtest.o
	gcc randtest.o -o randtest
randtest.o: randtest.asm
	nasm -f elf -F stabs randtest.asm

测试:

[root@bogon randtest]# make
nasm -f elf -F stabs randtest.asm
gcc randtest.o -o randtest
[root@bogon randtest]# ./randtest 

Here is an array of 36 32-bit random numbners:
 783082802 2015556527  543193849 2039226355  941006786   31398675
1774612191 1481082542  470873846  116734738   14801476  962009402
 288935524  784925144 2104709381 1237311754  601393386 1134661054
1752141735  528512928  848300003  858978037 1617820568  623786287
 291301057 1585022978   84190193 1438304756 1614336276  950412687
1100380723   12131855  632155963 1232307843 1616421653  740413255

Here is an array of 36 16-bit random numbners:
     13695      44098      46752      34032      29728      43189
     56002      11884       7596      32048      13189      35372
     55967      56808      42628      39838      30920      16414
     22532      22846       8920      39697      20276      30563
      6695      64733      55417       6325      45441      17810
     14986      23603      57495      36424      42387      23462

Here is an array of 36 8-bit random numbners:
       156          4        147        110        230         22
       243        234          9         21         68        110
       155        132        127         66         98        228
        73        162        240         77        202        215
        75        223        152        239        254         10
        54        136         65         50        245        211

Here is an array of 36 7-bit random numbners:
        50          0        121         61        123        110
        38         49         20         99        114        115
        92         21          8         11         29         98
        75        103         37         92         26         45
        10        113        100         70         80         75
         6         89         60          5         95        127

Here is an array of 36 4-bit random numbners:
         5         12         10         15          9         13
        11          9          0          8          8         15
        11          3          7         15         15         12
         4          9          9          6         13          1
        11          1         11          0          9         11
         0          9         11          4         15         12

@G8iqJJt12Oh8FKKEINTmIvq6ag7RXTAU5TkF9xJ3GaZBkMPiRU7jzFMxKmfhqhySz9Xt7



  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嗨!对于逆向学习汇编语言学习笔记,我可以给你一些基本的指导。首先,汇编语言是一种低级语言,它与计算机的底层硬件密切相关。逆向工程则是通过分析和理解已编译的程序来获取程序的内部信息。 以下是一些学习汇编语言和逆向工程的建议: 1. 学习基础知识:了解计算机体系结构、寄存器、内存和指令集等基础概念是必要的。可以先阅读相关的书籍或在线教程,掌握这些基本概念。 2. 掌握汇编语言的语法和指令集:每种计算机体系结构都有自己的汇编语言语法和指令集。选择一种你感兴趣的体系结构(如x86、ARM等),并学习它的汇编语言。 3. 练习编写和调试汇编代码:通过编写简单的汇编代码来熟悉语法和指令集。使用调试器来单步执行代码并观察寄存器和内存的变化。 4. 分析已编译程序:选择一个目标程序进行逆向分析。使用反汇编器将程序转换为汇编代码,并分析代码的逻辑和功能。这有助于理解程序的结构和运行过程。 5. 使用调试器进行动态分析:通过调试器来动态地执行程序,并观察程序在运行时的行为。使用断点、内存查看器和寄存器查看器等工具来分析程序的状态和数据。 6. 学习逆向工程工具和技术:了解常用的逆向工程工具和技术,如IDA Pro、OllyDbg、Ghidra等。掌握这些工具的使用可以提高你的逆向分析能力。 7. 参考优秀资源:阅读与逆向工程和汇编语言相关的书籍、论文和博客,关注相关的社区和论坛。与其他逆向工程师交流经验也是很有帮助的。 记住,逆向工程是一个需要耐心和实践的过程。持续学习和实践将帮助你提高逆向分析的技能。祝你在学习汇编语言和逆向工程的过程中取得好成果!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值