Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Random number within a certain range in ASM.

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
Dr.Disrespect
Grandmaster Cheater
Reputation: 3

Joined: 17 Feb 2016
Posts: 526

PostPosted: Sun Mar 27, 2016 9:33 am    Post subject: Random number within a certain range in ASM. Reply with quote

I still cannot figure out how to get a random number within a certain range in ASM after one day of research. Sad

ParkourPenguig taught me about this, but I am too stupid to understand it:

Code:

----------This code is being used to get a random number from 1-10
call rand
xor edx,edx
mov ecx,#10
div ecx
test edx,edx
// do something based on whether edx == 0

My question is: if edx equals 0, what does that mean? What is the value of  the randomly generated number? Is it stored in ah?


I also did some research on google and found the following snippet:
Code:

-------This code is being used to generate a random number from 0-9
mov  ax, dx
xor  dx, dx
mov  cx, 10   
div  cx       ; here dx contains the remainder of the division - from 0 to 9

add  dl, '0'  ; to ascii from '0' to '9'


I find it difficult to understand both of them. Say if I want to generate a number from 0-59, how should I do it? Addition to that, all the registers are used in game, so where should I push them first and pop them later?
Back to top
View user's profile Send private message
Zanzer
I post too much
Reputation: 126

Joined: 09 Jun 2013
Posts: 3278

PostPosted: Sun Mar 27, 2016 10:34 am    Post subject: Reply with quote

Take yourself back to elementary school and remember that little concept known as a remainder. Smile
When you have any number in the known or unknown universe and you divide it by another number, it may not divide evenly.
Well, when you divide a number by 10, your possible remainders are 0-9.
When you divide a number by 6, your possible remainders are 0-5.
When you divide a number by 10000, your possible remainders are 0-9999.
There seems to be a pattern here! You can clearly see now how you get a random number between 0 and any other number.
But now lets say you want a number between 100 and 200, inclusive.
So if you divide by 101, you'll get back a value of 0-100. So now all I need to do is add 100 to the result!

Just an observation about your posts... you should probably ask these types of follow-up questions within the same thread.
That way if someone in the future has a similar question, they can do a search and easily find the whole chain of details discussing the topic.
Back to top
View user's profile Send private message
++METHOS
I post too much
Reputation: 92

Joined: 29 Oct 2010
Posts: 4197

PostPosted: Sun Mar 27, 2016 10:42 am    Post subject: Reply with quote

Yes, it's just a 'fancy' way to do simple math.
Back to top
View user's profile Send private message
Dr.Disrespect
Grandmaster Cheater
Reputation: 3

Joined: 17 Feb 2016
Posts: 526

PostPosted: Sun Mar 27, 2016 10:42 am    Post subject: Reply with quote

Zanzer wrote:
Take yourself back to elementary school and remember that little concept known as a remainder. Smile
When you have any number in the known or unknown universe and you divide it by another number, it may not divide evenly.
Well, when you divide a number by 10, your possible remainders are 0-9.
When you divide a number by 6, your possible remainders are 0-5.
When you divide a number by 10000, your possible remainders are 0-9999.
There seems to be a pattern here! You can clearly see now how you get a random number between 0 and any other number.
But now lets say you want a number between 100 and 200, inclusive.
So if you divide by 101, you'll get back a value of 0-100. So now all I need to do is add 100 to the result!

Just an observation about your posts... you should probably ask these types of follow-up questions within the same thread.
That way if someone in the future has a similar question, they can do a search and easily find the whole chain of details discussing the topic.


Thank you Zaner. I think I need to know how div works in ASM, I will google that. And, yeah, my math sucks... Sad

Edit:
@ ++METHOS, thank you.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 150

Joined: 06 Jul 2014
Posts: 4657

PostPosted: Sun Mar 27, 2016 11:45 am    Post subject: Reply with quote

From this reference:
Quote:
DIV r/m32 - Unsigned divide EDX:EAX by r/m32, with result stored in EAX = Quotient, EDX = Remainder.

r/m32 means that this instruction uses a 32-bit register or memory location for this operand. EDX:EAX means that you're using a 64-bit value with the lower 32-bits in EAX and the upper 32-bits in EDX. You should know what a quotient and remainder is from primary school.
Code:
call rand      // puts a random number into EAX
xor edx,edx    // makes EDX 0 to make sure you're only dividing EAX by a number
mov ecx,#10    // moves 10 (decimal) into ECX.
div ecx        // divides EDX:EAX (the random number) by ECX (10)
// remainder is stored in EDX, which is now effectively a pseudo-random value between 0 and 9 inclusive.
// do whatever you want to with it from here.

If you're ever in doubt of whether or not a register was modified, you can use pushad at the beginning of the script and popad at the end of your script to save and restore all general-purpose registers. Just make sure the stack is balanced between them.

I've attached an example of how I'd go about doing this.



RandomNumberGenerator.CT
 Description:
Spits out pseudorandom numbers. Attach to any 32-bit process with msvcrt.dll loaded.

Download
 Filename:  RandomNumberGenerator.CT
 Filesize:  2.82 KB
 Downloaded:  692 Time(s)


_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
Dr.Disrespect
Grandmaster Cheater
Reputation: 3

Joined: 17 Feb 2016
Posts: 526

PostPosted: Sun Mar 27, 2016 12:31 pm    Post subject: Reply with quote

ParkourPenguin wrote:
From this reference:
Quote:
DIV r/m32 - Unsigned divide EDX:EAX by r/m32, with result stored in EAX = Quotient, EDX = Remainder.

r/m32 means that this instruction uses a 32-bit register or memory location for this operand. EDX:EAX means that you're using a 64-bit value with the lower 32-bits in EAX and the upper 32-bits in EDX. You should know what a quotient and remainder is from primary school.
Code:
call rand      // puts a random number into EAX
xor edx,edx    // makes EDX 0 to make sure you're only dividing EAX by a number
mov ecx,#10    // moves 10 (decimal) into ECX.
div ecx        // divides EDX:EAX (the random number) by ECX (10)
// remainder is stored in EDX, which is now effectively a pseudo-random value between 0 and 9 inclusive.
// do whatever you want to with it from here.

If you're ever in doubt of whether or not a register was modified, you can use pushad at the beginning of the script and popad at the end of your script to save and restore all general-purpose registers. Just make sure the stack is balanced between them.

I've attached an example of how I'd go about doing this.

Thank you so much for the explanation and the excellent example, ParkourPenguin. Very Happy Can I do something to pay you back? You really helped me a lot.

Update:
I have studied your example. Do you mind if I ask couple questions about it?
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 150

Joined: 06 Jul 2014
Posts: 4657

PostPosted: Sun Mar 27, 2016 1:40 pm    Post subject: Reply with quote

Of course you can ask questions about it. There are a few other miscellaneous things in there (i.e. threads, calls to Sleep and VirtualFree), but I'll answer any questions you have.

And don't worry about paying me back; I like messing around with this kind of stuff.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
Dr.Disrespect
Grandmaster Cheater
Reputation: 3

Joined: 17 Feb 2016
Posts: 526

PostPosted: Sun Mar 27, 2016 3:24 pm    Post subject: Reply with quote

ParkourPenguin wrote:
Of course you can ask questions about it. There are a few other miscellaneous things in there (i.e. threads, calls to Sleep and VirtualFree), but I'll answer any questions you have.

And don't worry about paying me back; I like messing around with this kind of stuff.

ParkourPenguin, you are really a nice guy and it's great to have you here.

My questions are:
1.
Code:

mov ebx,[lowerBound] //10
mov ecx,[upperBound] //20
cmp ecx,ebx
cmovl ecx,ebx
inc ecx
sub ecx,ebx
idiv ecx
add edx,ebx
mov [myRandomNumber],edx


I think this part is the key part and I try to understand it. For example, if ecx == 20 and ebx ==10, after "inc ecx", ecx == 21, then after "sub ecx,ebx", ecx ==11. Then after "idiv ecx", edx:eax is divided by ecx, which is 11. The value in EAX is the random number and EDX is 0, so what is actually happening is EAX/11? Am I right up to this point? So, EDX keeps the remainder of EAX/11, which can be 0-10. Do I understand correctly?

2. Why do I need "[shouldExit]"? I don't see any change to the value of it, it's always 0 and the timer keeps running without being stopped. Update: Oh, i kinda get the idea, it is a global variable used to stop the timer if needed.

3. The "free memory ,return" part. I don't know why you did this:
Code:

pop eax
push 8000
push 0
push newmem
push eax
jmp kernel32.VirtualFree
db CC CC CC CC CC CC

But I think I just need to memorize it as a format to make it work. Very Happy

4. You push [interval] before calling "kernel32.sleep", I suppose this function takes one argument, which is the interval of the timer, right?

5. I only know how to use the template in "Code Injection", so how do I implement this to "Code Injection"? "shouldExit" kinda confuses me. Smile

6. If I want to generate 2 numbers, how to use an array to do that? Like this?
Code:

myRandomNumber:
dd 0 0 0 0    <-------------------- Does this define an array?


If an array is correctly defined, how to traverse it in ASM? The number of registers are so limited..... Sad I wish there were 16 registers that I can use...


Thanks in advance. Sorry, it's more than a couple of questions. Very Happy
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 150

Joined: 06 Jul 2014
Posts: 4657

PostPosted: Sun Mar 27, 2016 5:44 pm    Post subject: Reply with quote

1. When you divide an integer (dividend) by another integer (divisor) and try to get the remainder, the maximum value of the remainder is one less than the divisor. This is because that if it was equal to the divisor, then the divisor would perfectly go into the dividend without any remainder- aka, the remainder resets to 0.

So, in order to make the possible range of values inclusive, you need to add 1 to the maximum value it could return.

Analyzing the code gives:
Code:
mov ebx,[lowerBound]       // moves data into registers to work with it
mov ecx,[upperBound]       // ^
cmp ecx,ebx                // tests whether or not the bounds make sense
cmovl ecx,ebx              // corrects upper bound register if needed
inc ecx                    // allows [upperBound] to be a possible result
sub ecx,ebx                // gets the range of values it should produce
idiv ecx                   // signed division to get the remainder
add edx,ebx                // adds lower bound to result
mov [myRandomNumber],edx  // edx is now between [upperBound] and [lowerBound] inclusive. Do whatever you want with it.


2,3,4: This is all the miscellaneous stuff. I'm not hooking any particular instruction, so the process CE is attached to won't ever run this code on it's own. That is, unless I tell it to by creating a thread. Most of the code you referenced in 2-4 deals with thread management; I'll explain it all.

Code:
createthread(newmem)
Tells the process to make a new thread that starts executing the asm at the address newmem.

Code:
push [interval]
call kernel32.Sleep
Calling kernel32.Sleep will suspend the current thread for the time (in milliseconds) you pass to it. This not only lets us see the random number it makes before it makes another one, but it also prevents this thread from hogging all the CPU.

Code:
cmp [shouldExit],0
je asTimeGoesBy
While this isn't important while the script is running, it is very important when you try to disable the script. If you didn't have that at all and instead just had an infinite loop, then the thread would continue running this asm indefinitely (even if you disable the script).

There are a few ways to tell a thread to stop running, but one of the easiest is to execute a ret instruction. This instruction pops a 4-byte value from the stack and jumps to it. In the case of a thread, it returns to a place that destroys the thread. Just make sure the stack is at where it started when you return.

However, if you just simply return, then the memory is still there. When you enable the script again, it will allocate new memory. This is known as memory leak, and it's bad.

One simple solution you may think of is to put dealloc(newmem) in the [DISABLE] section; however, this will crash the process. Remember that the thread is still running when the [DISABLE] section is run. If CE frees that memory remotely and the thread is still using it, then that will result in a segfault, crashing the process. This leads us to...
Code:
pop eax
push 8000
push 0
push newmem
push eax
jmp kernel32.VirtualFree
kernel32.VirtualFree is a subroutine that's meant to be called.

When you call an address, the call first pushes the address of the instruction after it onto the stack, then jumps to the address given to it. It does this because it expects to eventually reach a ret instruction. However, as you can see, I'm jumping to it instead. This means that when it gets to the ret instruction, it won't return to the memory it just freed; instead, it returns to the last thing I pushed onto the stack. In this case, due to the pop eax / push eax, that's the return address of this thread. So, when kernerl32.VirtualFree returns, it will destroy the thread.

All the other things I pushed are specified in this documentation: 8000 is the dwFreeType (MEM_RELEASE), 0 is the dwSize (must be 0 for MEM_RELEASE), and newmem is the address where you want to free memory.


Also, that last line (db CC CC CC...) is just spacing so I know where exactly the code ends and where my variables begin. The byte CC is technically the interrupt 3 instruction (used by debuggers; also used for padding). Putting these here also helps me align the data after it on a 4-byte boundary, but that's usually only for my own tranquility.

5: All you need to understand is what this does:
Code:
mov ebx,#10
mov ecx,#20
sub ecx,ebx
div ecx     // note: use idiv for signed values.
add edx,ebx
// edx is now between 10 and 19 (inclusive).
Do whatever you want with edx from that point.
_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
Dr.Disrespect
Grandmaster Cheater
Reputation: 3

Joined: 17 Feb 2016
Posts: 526

PostPosted: Sun Mar 27, 2016 6:58 pm    Post subject: Reply with quote

ParkourPenguin wrote:
1. When you divide an integer (dividend) by another integer (divisor) and try to get the remainder, the maximum value of the remainder is one less than the divisor. This is because that if it was equal to the divisor, then the divisor would perfectly go into the dividend without any remainder- aka, the remainder resets to 0.

So, in order to make the possible range of values inclusive, you need to add 1 to the maximum value it could return.

Analyzing the code gives:
Code:
mov ebx,[lowerBound]       // moves data into registers to work with it
mov ecx,[upperBound]       // ^
cmp ecx,ebx                // tests whether or not the bounds make sense
cmovl ecx,ebx              // corrects upper bound register if needed
inc ecx                    // allows [upperBound] to be a possible result
sub ecx,ebx                // gets the range of values it should produce
idiv ecx                   // signed division to get the remainder
add edx,ebx                // adds lower bound to result
mov [myRandomNumber],edx  // edx is now between [upperBound] and [lowerBound] inclusive. Do whatever you want with it.


2,3,4: This is all the miscellaneous stuff. I'm not hooking any particular instruction, so the process CE is attached to won't ever run this code on it's own. That is, unless I tell it to by creating a thread. Most of the code you referenced in 2-4 deals with thread management; I'll explain it all.

Code:
createthread(newmem)
Tells the process to make a new thread that starts executing the asm at the address newmem.

Code:
push [interval]
call kernel32.Sleep
Calling kernel32.Sleep will suspend the current thread for the time (in milliseconds) you pass to it. This not only lets us see the random number it makes before it makes another one, but it also prevents this thread from hogging all the CPU.

Code:
cmp [shouldExit],0
je asTimeGoesBy
While this isn't important while the script is running, it is very important when you try to disable the script. If you didn't have that at all and instead just had an infinite loop, then the thread would continue running this asm indefinitely (even if you disable the script).

There are a few ways to tell a thread to stop running, but one of the easiest is to execute a ret instruction. This instruction pops a 4-byte value from the stack and jumps to it. In the case of a thread, it returns to a place that destroys the thread. Just make sure the stack is at where it started when you return.

However, if you just simply return, then the memory is still there. When you enable the script again, it will allocate new memory. This is known as memory leak, and it's bad.

One simple solution you may think of is to put dealloc(newmem) in the [DISABLE] section; however, this will crash the process. Remember that the thread is still running when the [DISABLE] section is run. If CE frees that memory remotely and the thread is still using it, then that will result in a segfault, crashing the process. This leads us to...
Code:
pop eax
push 8000
push 0
push newmem
push eax
jmp kernel32.VirtualFree
kernel32.VirtualFree is a subroutine that's meant to be called.

When you call an address, the call first pushes the address of the instruction after it onto the stack, then jumps to the address given to it. It does this because it expects to eventually reach a ret instruction. However, as you can see, I'm jumping to it instead. This means that when it gets to the ret instruction, it won't return to the memory it just freed; instead, it returns to the last thing I pushed onto the stack. In this case, due to the pop eax / push eax, that's the return address of this thread. So, when kernerl32.VirtualFree returns, it will destroy the thread.

All the other things I pushed are specified in this documentation: 8000 is the dwFreeType (MEM_RELEASE), 0 is the dwSize (must be 0 for MEM_RELEASE), and newmem is the address where you want to free memory.


Also, that last line (db CC CC CC...) is just spacing so I know where exactly the code ends and where my variables begin. The byte CC is technically the interrupt 3 instruction (used by debuggers; also used for padding). Putting these here also helps me align the data after it on a 4-byte boundary, but that's usually only for my own tranquility.

5: All you need to understand is what this does:
Code:
mov ebx,#10
mov ecx,#20
sub ecx,ebx
div ecx     // note: use idiv for signed values.
add edx,ebx
// edx is now between 10 and 19 (inclusive).
Do whatever you want with edx from that point.


Thank you ParkourPenguin, I do understand the crucial part of the code now and generating a random number in ASM is not a problem to me anymore, thanks to you and all the people who have helped me. Very Happy
Now I am working on another issue: array. I will post a CT after I finish it. If you have time, you are more than welcomed to exam it. Very Happy

Edit:
@ParkourPenguin, I have made a CT based on your example. It is meant to resolve this issue: http:http://forum.cheatengine.org/viewtopic.php?t=588776[/u]

If you have time to take a look at it, I will be very grateful. Smile



TribeGold.CT
 Description:

Download
 Filename:  TribeGold.CT
 Filesize:  5.53 KB
 Downloaded:  500 Time(s)

Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites