Some programming questions I have.

Started by
8 comments, last by Khatharr 11 years ago

Some thoughts that I had. Not specific to any language. But if the answers depends on the language, I know c++, java and actionscript.

1- When you declare an integer: "int i = 0", what is int? Is it a class? How does it work inside? Is there a source code for how the int works?

2- The same doubt about structures: if, else, for, etc (I think we call them structures). What are they? How do they work? Is there a source code?

3- Is it possible to make a pointer point to a specific memory address?

int * p;

p = 0x00FF32

Is it possible somehow?

4- Is it possible to know what type of variable the memory address 0x00FF32 is containing? What other info I can get about this address?

Advertisement
1. I know in c++ and java, int is a primitive type. That means it is not a class. In memory, it is a sequence of bits that represent an integer. In java, there is also the Integer class. It's the object version of int.

2. if, else, for and while translate to one or more branch instructions. Branch instructions are used to jump to a different point in your program.

3. If it is possible, it won't be useful. It might be pointing to a place you shouldn't point at, or it might be pointing to something different everytime you run the program, or it can vary depending on the compiler you use, or the operating system the program was compiled on.

4. c++ has RTTI to lets you find the type of an object. But it is not useful to use it on magic number pointers.

2- The same doubt about structures: if, else, for, etc (I think we call them structures). What are they? How do they work? Is there a source code?

Typically called 'statements' (if statement, while statement, etc...). Structures are something else.

They boil down to assembly language, and work like this in the CPU:
Line 54: if(x) JumpTo (line 55), otherwise jump to (line 58) 
Line 55:      stuff
Line 56:      more stuff
Line 57:      other stuff
Line 58: Back to normal
Except instead of jumping to 'lines', it's actually jumping to locations in memory when the next assembly instruction is.

The assembly has built-in commands/op-codes/instructions that the CPU provides in hardware (or in software from the OS). The instructions contain some simple stuff like addition, subtraction, binary AND, OR, XOR, etc... and a little bit of program flow, like if-then-goto.

jump-if-less-than
jump-if-greater-than
jump-if-equal-to

C++ if() statements are compiled down to these assembly instructions.
Same with for() and while() and other statements.

for(int x = 0; x < 10; x++) is basically:
0x00F133: set var 'x' to 10
0x00F134: if x is not less than 10, jump to 0x00F138
0x00F135:      <inside of the for() loop>
0x00F136:      set var 'x' to (x + 1)
0x00F137:      jump back to 0x00F134 again
0x00F138: ...code that is after the for() statement ends...

3- Is it possible to make a pointer point to a specific memory address?

In most situations it's not very useful, but in some low-level situations on specific hardware you might know for sure that at a certain address is a certain resource that is updated by the hardware or operating system. On PCs, however, our programs run in virtual memory where the addresses we see aren't the actual addresses in memory, because the OS is protecting our program from accidentally writing to areas it shouldn't be.

4- Is it possible to know what type of variable the memory address 0x00FF32 is containing? What other info I can get about this address?

Not in C++. Memory is memory. It's how you interpret the memory that matters, so your code needs to tell the computer how to interpret the memory.

Example:
int main()
{
    int myInt = 357;
    std::cout << myInt << std::endl;
    
    float *myFloat = (float*)(&myInt);
    std::cout << *myFloat << std::endl;
    
    return 0;
}
'myInt' is just a bunch of 1s and 0s. The data has no meaning outside of how int interprets the 1s and 0s.
If I pretend it's a float, the 1s and 0s are treated entirely differently when float interprets it.

Thank you. So these primitive types are also made with assembly right? The assembly code for them just allocate some memory for them and tells how the high-level language should interpret the 0s and 1s that are allocated.

About the other questions about memory addresses, I was thinking like this: If you could scan all the memory adresses and see what type of variables they were, you could do something with them. Like I have a game where there is a tutorial where there is a text that says "Jump over the spikes".

I would make something like this:


for(>>from 0x000000 to the last adress<<){
	if(>>current adress is a String<<){
		if(>>current adress is equal to "Jump over the spikes"<<){
			String myString = "ahah I changed something in the game";
			>>make the current adress equal to myString<<
		}
	}
}

Nothing is "made from assembly", assembly is just a way for humans to name the instructions the CPU understands.

Assembly language doesn't know anything about "types" either, it just has instructions which operate on data of various sizes (typically 8, 16, 32 bits but also vector types as well) and it is up to the assembly programmer to use the correct instructions for the correct data (in the case of high level languages, the compiler is the assembly programmer, and it knows which types of data reside at specific addresses, so it makes sure the correct types of instructions are used).

You can easily scan for strings in code by dumping the executable into a hex viewer (Visual Studio will display a hex dump if you rename the file .bin instead of .exe), assuming the strings aren't encrypted in some way.

Looking for other types is more difficult since you need to know the type of the variable that occupies the address.

To read memory from a running process have a look at http://msdn.microsoft.com/en-gb/library/windows/desktop/ms680553%28v=vs.85%29.aspx (assuming Windows).

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

You're basically talking about reverse engineering the memory. This pdf might be informative.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

So these primitive types are also made with assembly right? The assembly code for them just allocate some memory for them and tells how the high-level language should interpret the 0s and 1s that are allocated.

Sortof. 'primitive types' vary from language to language, but basically in the hardware you have two types: integers, and floats. 32 bit integers, 64 bit integers, 32 bit floats, 64 bit floats, possibly other sizes as well like 16 bit floats or 128 bit floats or integers. This depends on the hardware. They aren't 'made with' anything, except binary in memory. Assembly modifies them, telling the OS to do some operation implemented in the actual hardware of the CPU.

bool's in C++ are just integers. 0 = false, anything else is true.
char's are just integers. We just assigned permanent numbers to specific letters and symbols. See ASCII chart. The number 65 is 'A', 66 is 'B', 97 is 'a', 98 is 'b'. 37 is '%'.

Strings are just multiple chars in a row. C and C++ don't have a native 'string' type, but they have arrays of chars, and C++ has std::string which is a class that wraps an array of chars for convenience and safety.

About the other questions about memory addresses, I was thinking like this: If you could scan all the memory adresses and see what type of variables they were, you could do something with them. Like I have a game where there is a tutorial where there is a text that says "Jump over the spikes".

I would make something like this:

for(>>from 0x000000 to the last adress<<){
	if(>>current adress is a String<<){
		if(>>current adress is equal to "Jump over the spikes"<<){
			String myString = "ahah I changed something in the game";
			>>make the current adress equal to myString<<
		}
	}
}


Well, many games load their data from files, so you can use a program to edit the data of the files.
The executable itself (.exe, .dmg, etc...) is just a file with data as well. Data is just binary, and it only depends on how you treat the binary. I can pretend a string is a float, or a float is a string. Doing so will give me jibberish, but it'll work.
The computer doesn't store what *type* of variable is at a certain location, it just stores binary. The program decides how to use that binary. This is important because A) it saves memory (don't store what you don't need), and B) you occasionally want to treat the same chunk of memory as different types.

So, if you open an executable in something like an hex editor (such as HxD), you can directly edit the binary. Doing so can obviously break the game if you accidentally edited the wrong value, so create a backup copy before editing it. Looking through the binary, you might notice patterns. HxD shows the binary as hexadecimal value (hence the term 'hex editor') and as chars, so if you're looking for a string, you might be able to spot it, or maybe do a Ctrl+F for it. Then you can modify it, save it, then run the executable. Note: Because assembly is referring to certain memory addresses (jump to 0x0FA3B4 and etc...), you can't remove any bytes or it'll throw off the memory jumps, so make sure anything you replace is the same size of bytes as previously. (Any strings you are modifying can't be larger than what you are replacing, and if it's smaller, pad it out with spaces or something so it's the same length).

Hmm, that made things more clear to me. Thank you all. I have tested HxD, but couldn't do much. I could change a string of my own test program that I made. In other programs I just couldn't find the strings that I saw on them in the hex editor. Actually I don't have many programs to test here in this PC. Also, paradigm shifter, I couldn't implement that function in the link you've passed. I've included the windows.h library and all but the code didn't compile. Guess I'll take a better look at it some time.

Anyway, three more questions that came to my mind:

1- The memory address allocated to things don't always change every time you run your programs? How text editors change memory values and when you execute the program these values are the right ones?

2- Isn't it possible to change memory and get the desired effects at run-time? Hex editors don't do that.

3- Isn't it possible to do the things you do on hex editor on your code? so you can automate stuff?

In other programs I just couldn't find the strings that I saw on them in the hex editor.

Then that's probably because the other programs don't have the strings within the executable as string literals, and instead load the strings from files. This is very common, so you can flexibly change text during development, so it's easier to patch, and so localization is just a matter of pointing at a new language file instead of recompiling the executable for every language.

1- The memory address allocated to things don't always change every time you run your programs?

The memory of the executable stays the same, relative to the executable. The executable is a file. The data at the location 50 bytes into the file is always 50 bytes into the file.
When the program is running, first it is loaded into RAM, and then it can (and does) allocate new memory in RAM do work on. The hex editor can't edit that memory while it's running, though it can edit the assembly instructions to change what it does with that memory or where it looks for the data. That's a bit beyond my knowledge though.

2- Isn't it possible to change memory and get the desired effects at run-time? Hex editors don't do that.
3- Isn't it possible to do the things you do on hex editor on your code? so you can automate stuff?

I'm not sure what you mean by 'automating' it, but yes, you can interpret and edit any chunk of RAM that your program controls however you want, within your program.

The example I posted above:


int main()
{
    int myInt = 357; //The program makes an int.
    std::cout << myInt << std::endl;
    
    float *myFloat = (float*)(&myInt); //The program pretends it's a float.
    std::cout << *myFloat << std::endl;

    *myFloat = 2000.0f; //The program edits the memory while pretending it's a float.
    myInt = 800; //The program edits the memory while pretending it's an int.
    
    return 0;
}

But hey, if you want an external program that can edit RAM while another program is running, I'm sure you can do that too.

See this website (from a different GameDev.net member), which focuses on some memory modification software she developed.

I'll just leave this here... (Do the tutorial. Also, study up on ASM so you can tell what's going on when you use the disassembler.)
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement