uint8_t Array - Data inside memory - c

I have a question to a behavior I detect with the gdb.
First I compiled this small program with the gcc on a 64bit machine:
#include <stdio.h>
#include <inttypes.h>
void fun (uint8_t *ar)
{
uint8_t i;
for(i = 0; i<4; i++)
{
printf("%i\n",*(&ar[0]+i));
}
}
int main (void)
{
uint8_t ar[4];
ar[0] = 0b11001100;
ar[1] = 0b10101010;
ar[2] = 0b01010110;
ar[3] = 0b00110011;
fun(ar);
return 0;
}
Then I look with the gdb to the memory of ar:
(gdb) p/t ar
$7 = {11001100, 10101010, 1010110, 110011}
(gdb) x ar
0x7fffffffe360: 00110011010101101010101011001100
(gdb) x 0x7fffffffe360
0x7fffffffe360: 00110011010101101010101011001100
(gdb) x 0x7fffffffe361
0x7fffffffe361: 11111111001100110101011010101010
(gdb) x 0x7fffffffe362
0x7fffffffe362: 01111111111111110011001101010110
(gdb) x 0x7fffffffe363
0x7fffffffe363: 00000000011111111111111100110011
I saw that the array of uint8_t was collect together to an 32 bit field. For the next addresses this will only push to the right.
&ar[0] -> {ar[3],ar[2],ar[1],ar[0]}
&ar[1] -> {xxxx,ar[3],ar[2],ar[1]}
&ar[2] -> {xxxx,xxxx,ar[3],ar[2]}
&ar[3] -> {xxxx,xxxx,xxxx,ar[3]}
It's a bit strange and I want to know: Why this will happen and can I rely on this behavior? Is this only typically for gcc or is this a handling standard?

In gdb, x just prints out whatever is in the memory location, regardless of its type in the C code. You're just getting some defaults (or previously used formats) for the width(4 bytes in your case) and format.
Do e.g. x/b ar to print the location as bytes. and do help x for more info.
If you print it as a anything other than a byte, endianess of your processor will determine how the memory is interpreted though.
Use p to take the type into account, as in p ar

It has to do with endianness:
In a x64, and every other little-endian machine, the data of value 0x12345678 is put into memory in the form 78 56 34 12, i. e. with the lowest significant byte first.
The debugger knows that and shows it to you in this way.
Expressed in hex, making your data easier to read, it looks this way:
Your memory is filled with
CC AA 56 33 FF 7F 00
which makes
the value at offset 0 3356AACC
the value at offset 1 FF3356AA
the value at offset 2 7FFF3356
the value at offset 3 007FFF33

Related

How to read and change value from memory in Linux?

The code inside main.c
#include <stdio.h>
#include <unistd.h>
int main() {
int c_variable = 0; // the target
for(int x = 0; x < 100; x++) {
c_variable += 5; // increase by 5 to change the value of the int
printf("%i\n", c_variable); // print current value
sleep(8); // sleep so I have time to scan memory
}
return 0;
}
What I am trying to achieve is to read the integer c_variable and then to modify it inside another .c program. I am on linux so I did ps -A | grep main and got the PID of the running program. I then did sudo scanmem PID and entered the current value of c_variable a few times. I was left with three memory addresses and executing the command set 500 changed the value the program printed, effectively changing the memory address' value to 500 instead of 35 or whatever the program was currently at. I then executed the following code
#include <stdio.h>
int main() {
const long unsigned addr = 0x772d85fa1008; // one of the three addresses from scanmem
printf("%lu\n", addr);
return 0;
}
but I got some random long string of numbers, not the current number. The tutorials and answers I have read on how to read and write memory on linux does not have to use long unsigned but can use char* or just int* instead. My memory address seems to be a bit long, I have not see memory addresses that long before. Anyhow, how do I read and write the memory address of the integer c_variable?
Edit: the output of scanmem looks something like this
info: we currently have 3 matches.
3> list
[ 0] 7771ff64b090, 6 + 1e090, stack, 20, [I64 I32 I16 I8 ]
[ 1] 7771ff64b5d8, 6 + 1e5d8, stack, 20, [I64 I32 I16 I8 ]
[ 2] 7771ff64b698, 6 + 1e698, stack, 20, [I32 I16 I8 ]
3> set 50
info: setting *0x7771ff64b090 to 0x32...
info: setting *0x7771ff64b5d8 to 0x32...
info: setting *0x7771ff64b698 to 0x32...
output
...
150
155
160
165
170
175
55
60
65
...
You're printing the actual address number, but in in decimal notation, not what is at the address.
const int *addr = (int *) 0x772d85fa1008;
printf("%d\n", *addr);
You have to declare addr as a pointer type. More specifically a pointer to an integer. Its value (0x772d85fa1008) holds the address of the integer.
Then, in the printf call you dereference it to obtain the actual integer stored at the address.
Although in practice I can't vouch for whether this is going to work, since memory in modern operating systems isn't as simple as you make it out to be. But I don't have enough knowledge to assess that.
Processes running under Linux generally have their own virtualized memory space. If you want to access memory space of another process, arrangements have been made in the Linux API, see shmctl, shmget, shmat, shmdt.

Seeing data stored on the stack

I have the following src:
1 #include<stdio.h>
2
3 int main(void) {
4 int i= 1337; // breakpoint after this value is assigned
!5 return 0;
6 }
In the asm from gdb I get:
!0x00000000004004f1 main+4 movl $0x539,-0x4(%rbp)
And I verified that $0x539 = 1337. How can I see the memory address where the value 1337 is stored? The value of the rbp memory address shows:
rbp 0x00007fffffffeb20
My thought was the rbp register would show the value 0x539, so where would I be able to find that in gdb (what command to use, etc)?
One interesting things I found was in doing:
>>> print i
$16 = 1337
>>> print &i
$17 = (int *) 0x7fffffffeb1c # how is this arrived at?
0x00007fffffffeb20 - 0x4 == 0x7fffffffeb1c
on x86 almost all constants will be addressed as a relative offset from a register. In this case the register is rbp [the frame address], and the relative offset is -4 bytes. i.e. the constant appears prior to the first instruction in main.
x64 addressing modes typically involve one of 3 possibilities:
a zero byte offset from a register address
a signed 8bit offset from a register address
a signed 32bit offset from a register address
(there is a 4th addressing mode, which is to load the value from a register - just for completeness!). In general, a compiler would prefer to emit those modes in the order I have listed them above (because they result in the Op code + an offset which will be either: 0bytes, 1byte, or 4bytes respectively - so the smaller the offset, the smaller the generated machine code will be).

Buffer overflow in C

I'm attempting to write a simple buffer overflow using C on Mac OS X 10.6 64-bit. Here's the concept:
void function() {
char buffer[64];
buffer[offset] += 7; // i'm not sure how large offset needs to be, or if
// 7 is correct.
}
int main() {
int x = 0;
function();
x += 1;
printf("%d\n", x); // the idea is to modify the return address so that
// the x += 1 expression is not executed and 0 gets
// printed
return 0;
}
Here's part of main's assembler dump:
...
0x0000000100000ebe <main+30>: callq 0x100000e30 <function>
0x0000000100000ec3 <main+35>: movl $0x1,-0x8(%rbp)
0x0000000100000eca <main+42>: mov -0x8(%rbp),%esi
0x0000000100000ecd <main+45>: xor %al,%al
0x0000000100000ecf <main+47>: lea 0x56(%rip),%rdi # 0x100000f2c
0x0000000100000ed6 <main+54>: callq 0x100000ef4 <dyld_stub_printf>
...
I want to jump over the movl instruction, which would mean I'd need to increment the return address by 42 - 35 = 7 (correct?). Now I need to know where the return address is stored so I can calculate the correct offset.
I have tried searching for the correct value manually, but either 1 gets printed or I get abort trap – is there maybe some kind of buffer overflow protection going on?
Using an offset of 88 works on my machine. I used Nemo's approach of finding out the return address.
This 32-bit example illustrates how you can figure it out, see below for 64-bit:
#include <stdio.h>
void function() {
char buffer[64];
char *p;
asm("lea 4(%%ebp),%0" : "=r" (p)); // loads address of return address
printf("%d\n", p - buffer); // computes offset
buffer[p - buffer] += 9; // 9 from disassembling main
}
int main() {
volatile int x = 7;
function();
x++;
printf("x = %d\n", x); // prints 7, not 8
}
On my system the offset is 76. That's the 64 bytes of the buffer (remember, the stack grows down, so the start of the buffer is far from the return address) plus whatever other detritus is in between.
Obviously if you are attacking an existing program you can't expect it to compute the answer for you, but I think this illustrates the principle.
(Also, we are lucky that +9 does not carry out into another byte. Otherwise the single byte increment would not set the return address how we expected. This example may break if you get unlucky with the return address within main)
I overlooked the 64-bitness of the original question somehow. The equivalent for x86-64 is 8(%rbp) because pointers are 8 bytes long. In that case my test build happens to produce an offset of 104. In the code above substitute 8(%%rbp) using the double %% to get a single % in the output assembly. This is described in this ABI document. Search for 8(%rbp).
There is a complaint in the comments that 4(%ebp) is just as magic as 76 or any other arbitrary number. In fact the meaning of the register %ebp (also called the "frame pointer") and its relationship to the location of the return address on the stack is standardized. One illustration I quickly Googled is here. That article uses the terminology "base pointer". If you wanted to exploit buffer overflows on other architectures it would require similarly detailed knowledge of the calling conventions of that CPU.
Roddy is right that you need to operate on pointer-sized values.
I would start by reading values in your exploit function (and printing them) rather than writing them. As you crawl past the end of your array, you should start to see values from the stack. Before long you should find the return address and be able to line it up with your disassembler dump.
Disassemble function() and see what it looks like.
Offset needs to be negative positive, maybe 64+8, as it's a 64-bit address. Also, you should do the '+7' on a pointer-sized object, not on a char. Otherwise if the two addresses cross a 256-byte boundary you will have exploited your exploit....
You might try running your code in a debugger, stepping each assembly line at a time, and examining the stack's memory space as well as registers.
I always like to operate on nice data types, like this one:
struct stackframe {
char *sf_bp;
char *sf_return_address;
};
void function() {
/* the following code is dirty. */
char *dummy;
dummy = (char *)&dummy;
struct stackframe *stackframe = dummy + 24; /* try multiples of 4 here. */
/* here starts the beautiful code. */
stackframe->sf_return_address += 7;
}
Using this code, you can easily check with the debugger whether the value in stackframe->sf_return_address matches your expectations.

How to skip a line doing a buffer overflow in C

I want to skip a line in C, the line x=1; in the main section using bufferoverflow; however, I don't know why I can not skip the address from 4002f4 to the next address 4002fb in spite of the fact that I am counting 7 bytes form <main+35> to <main+42>.
I also have configured the options the randomniZation and execstack environment in a Debian and AMD environment, but I am still getting x=1;. What it's wrong with this procedure?
I have used dba to debug the stack and the memory addresses:
0x00000000004002ef <main+30>: callq 0x4002a4 **<function>**
**0x00000000004002f4** <main+35>: movl $0x1,-0x4(%rbp)
**0x00000000004002fb** <main+42>: mov -0x4(%rbp),%esi
0x00000000004002fe <main+45>: mov $0x4629c4,%edi
void function(int a, int b, int c)
{
char buffer[5];
int *ret;
ret = buffer + 12;
(*ret) += 8;
}
int main()
{
int x = 0;
function(1, 2, 3);
x = 1;
printf("x = %i \n", x);
return 0;
}
You must be reading Smashing the Stack for Fun and Profit article. I was reading the same article and have found the same problem it wasnt skipping that instruction. After a few hours debug session in IDA I have changed the code like below and it is printing x=0 and b=5.
#include <stdio.h>
void function(int a, int b) {
int c=0;
int* pointer;
pointer =&c+2;
(*pointer)+=8;
}
void main() {
int x =0;
function(1,2);
x = 3;
int b =5;
printf("x=%d\n, b=%d\n",x,b);
getch();
}
In order to alter the return address within function() to skip over the x = 1 in main(), you need two pieces of information.
1. The location of the return address in the stack frame.
I used gdb to determine this value. I set a breakpoint at function() (break function), execute the code up to the breakpoint (run), retrieve the location in memory of the current stack frame (p $rbp or info reg), and then retrieve the location in memory of buffer (p &buffer). Using the retrieved values, the location of the return address can be determined.
(compiled w/ GCC -g flag to include debug symbols and executed in a 64-bit environment)
(gdb) break function
...
(gdb) run
...
(gdb) p $rbp
$1 = (void *) 0x7fffffffe270
(gdb) p &buffer
$2 = (char (*)[5]) 0x7fffffffe260
(gdb) quit
(frame pointer address + size of word) - buffer address = number of bytes from local buffer variable to return address
(0x7fffffffe270 + 8) - 0x7fffffffe260 = 24
If you are having difficulties understanding how the call stack works, reading the call stack and function prologue Wikipedia articles may help. This shows the difficulty in making "buffer overflow" examples in C. The offset of 24 from buffer assumes a certain padding style and compile options. GCC will happily insert stack canaries nowadays unless you tell it not to.
2. The number of bytes to add to the return address to skip over x = 1.
In your case the saved instruction pointer will point to 0x00000000004002f4 (<main+35>), the first instruction after function returns. To skip the assignment you need to make the saved instruction pointer point to 0x00000000004002fb (<main+42>).
Your calculation that this is 7 bytes is correct (0x4002fb - 0x4002fb = 7).
I used gdb to disassemble the application (disas main) and verified the calculation for my case as well. This value is best resolved manually by inspecting the disassembly.
Note that I used a Ubuntu 10.10 64-bit environment to test the following code.
#include <stdio.h>
void function(int a, int b, int c)
{
char buffer[5];
int *ret;
ret = (int *)(buffer + 24);
(*ret) += 7;
}
int main()
{
int x = 0;
function(1, 2, 3);
x = 1;
printf("x = %i \n", x);
return 0;
}
output
x = 0
This is really just altering the return address of function() rather than an actual buffer overflow. In an actual buffer overflow, you would be overflowing buffer[5] to overwrite the return address. However, most modern implementations use techniques such as stack canaries to protect against this.
What you're doing here doesn't seem to have much todo with a classic bufferoverflow attack. The whole idea of a bufferoverflow attack is to modify the return adress of 'function'. Disassembling your program will show you where the ret instruction (assuming x86) takes its adress from. This is what you need to modify to point at main+42.
I assume you want to explicitly provoke the bufferoverflow here, normally you'd need to provoke it by manipulating the inputs of 'function'.
By just declaring a buffer[5] you're moving the stackpointer in the wrong direction (verify this by looking at the generated assembly), the return adress is somewhere deeper inside in the stack (it was put there by the call instruction). In x86 stacks grow downwards, that is towards lower adresses.
I'd approach this by declaring an int* and moving it upward until I'm at the specified adress where the return adress has been pushed, then modify that value to point at main+42 and let function ret.
You can't do that this way.
Here's a classic bufferoverflow code sample. See what happens once you feed it with 5 and then 6 characters from your keyboard. If you go for more (16 chars should do) you'll overwrite base pointer, then function return address and you'll get segmentation fault. What you want to do is to figure out which 4 chars overwrite the return addr. and make the program execute your code. Google around linux stack, memory structure.
void ff(){
int a=0; char b[5];
scanf("%s",b);
printf("b:%x a:%x\n" ,b ,&a);
printf("b:'%s' a:%d\n" ,b ,a);
}
int main() {
ff();
return 0;
}

SSE shifting integers

I'm trying to understand how shifting with SSE works, but I don't understand the output gdb gives me. Using SSE4 I have a 128bit vector holding 8 16bit unsigned integers (using uint16_t). Then I use the intrinsic _mm_cmpgt_epi16 to compare them against some value, this function puts in all 0 or 1 bits into the bits used to store the ints. So far so good, using gdb I get:
(gdb) p/t sse_res[0]
$3 = {1111111111111111111111111111111111111111111111110000000000000000, 1111111111111111111111111111111111111111111111110000000000000000}
Then I would like to shift them to the right (is that correct?) so I just get a numerical value of 1 in case it's true. GDB then gives me an output which I don't understand:
(gdb) p/t shifted
$4 = {11101000000000010010000000000000110000000000000000011, 100111000000000001011000000000001001000000000000001111}
It's not even of the same length as the first, why is this? Just to try it out I used the following intrinsic to shift it one bit to the right:
shifted = _mm_srli_epi16(sse_array[i], 1);
I expected it to shift in just one zero at the right end of every 16bit block.
Update:
I wrote a small example to test the thing with the bitmask, it works fine, but I still don't understand gdbs behavior:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <tmmintrin.h>
#include <smmintrin.h>
void print128_num(__m128i vector)
{
uint16_t *values = (uint16_t*) &vector;
printf("Numerical: %i %i %i %i %i %i %i %i \n",
values[0], values[1], values[2], values[3], values[4], values[5],
values[6], values[7]);
}
int main (int argc, char **argv)
{
uint16_t nums[] = {1, 57, 33, 22, 88, 99, 9, 73};
__m128i *nums_sse = (__m128i*)(&nums);
print128_num(*nums_sse);
// vector of 42
__m128i mm42 = _mm_set1_epi16(42);
__m128i sse_res = _mm_cmpgt_epi16(*nums_sse, mm42);
printf("Result of the comparison\n");
print128_num(sse_res);
// bitmask
__m128i mask = _mm_set1_epi16(1);
__m128i finally = _mm_and_si128(sse_res, mask);
printf("Result of the masking\n");
print128_num(finally);
uint16_t* sse_ptr = (uint16_t*)(&finally);
uint32_t result = sse_ptr[0] + sse_ptr[1] + sse_ptr[2] + sse_ptr[3]
+ sse_ptr[4] + sse_ptr[5] + sse_ptr[6] + sse_ptr[7];
printf("Result: %i numbers greater 42\n", result);
return 0;
}
Breakpoint 1, main (argc=1, argv=0x7fff5fbff3b0) at example_comp.c:44
44 printf("Result: %i numbers greater 42\n", result);
(gdb) p/t sse_res
$1 = {11111111111111110000000000000000, 1111111111111111000000000000000011111111111111111111111111111111}
(gdb) p/t mask
$2 = {1000000000000000100000000000000010000000000000001, 1000000000000000100000000000000010000000000000001}
(gdb) p/t finally
$3 = {10000000000000000, 1000000000000000000000000000000010000000000000001}
(gdb) p result
$4 = 4
(gdb)
My gdb version: GNU gdb 6.3.50-20050815 (Apple version gdb-1472) (Wed Jul 21 10:53:12 UTC 2010)
Compiler flags: -Wall -g -O0 -mssse3 -msse4 -std=c99
I don't understand exactly what you're trying to do here, but maybe you can clarify it for us.
So, you have 8 signed integers packed in each of two variables, which you test for greater than. The result looks like it shows that the first 3 are greater, the next is not, the next 3 are greater, the last is not. (_mm_cmpgt_epi16 assumes signed integers in the reference I found.)
Then you want to tell if "it" is true, but I'm not sure what you mean by that. Do you mean they are all greater? (If so, then you could just compare the result against MAX_VALUE or -1 or something like that.)
But the last step is to shift some data to the right piecewise. Notice that is not the same variable as sse_res[0]. Were you expecting to shift that one instead?
Without knowing what was in the data before shifting, we can't tell if it worked correctly, but I assume that gdb is omitting the leading zeroes in its output, which would explain the shorter result.
0000000000011101 29 was 58 or 59
0000000000100100 36 was 72 or 73
0000000000011000 24 was 48 or 49
0000000000000011 3 was 6 or 7
0000000000100111 39 was 78 or 79
0000000000010110 22 was 44 or 45
0000000000100100 36 was 72 or 73
0000000000001111 15 was 30 or 31
Do these numbers look familiar?
Update:
Thanks for the updated code. It looks the integers are packed in the reverse order, and the leading zeroes left off in the gdb output.

Resources