LLDB Python API SBAddress constructor error - lldb

I'm trying to create an SB Value from an address value that I have, and I'm running into an issue with the SBAddress constructor. When I do this:
target = lldb.debugger.GetSelectedTarget()
pointer = target.FindFirstType('node_t').GetPointerType()
root = target.CreateValueFromAddress('root', lldb.SBAddress(0x100004058, target), pointer)
And then I run
root.GetValue()
I get something like 0x0000000100004041
Is there something wrong that I'm doing here with the constructor of the SBAddress?

You have to be careful about what's pointing to what to get this right. Is 0x100004058 the VALUE of the pointer you want to make a type from, or the LOCATION of that pointer? I suspect it is the former...
The memory at the address which is the value of the pointer holds an object of type "node_t". So when you want to make an SBValue out of that memory, the type you want is "node_t" not "node_t *".
However, if 0x100004058 were the location of the pointer, then making a value as a pointer to node_t at that address would be correct.
So, for instance, stopped here:
* thread #1: tid = 0x4ae2e3, function: take_void , stop reason = breakpoint 1.1
frame #0: 0x0000000100000f33 pointers`take_void at pointers.c:12
9 void
10 take_void(void *input)
11 {
-> 12 printf("Got pointer: %p.\n", input);
13 }
14
15 int
called from:
15 int
16 main()
17 {
18 struct Foo my_foo = {111, 222};
19 take_void (&my_foo);
20 return 0;
21 }
then:
(lldb) fr v -L
0x00007fff5fbff658: (void *) input = 0x00007fff5fbff670
The first address is the location of input, so:
(lldb) script
>>> ptr_type = lldb.target.FindFirstType('Foo').GetPointerType()
>>> root = lldb.target.CreateValueFromAddress("root", lldb.SBAddress(0x00007fff5fbff658, lldb.target), ptr_type)
>>> root.GetValue()
'0x00007fff5fbff670'
Which is what you expect. And:
>>> root = lldb.target.CreateValueFromAddress("root", lldb.SBAddress(0x00007fff5fbff670, lldb.target), type)
>>> root.GetValue()
That's right because structures don't have values. And:
>>> root.GetChildAtIndex(0).GetValue()
'111'
>>> root.GetChildAtIndex(1).GetValue()
'222'
Those were the values that I put in the fields, so that is right. And:
>>> root = lldb.target.CreateValueFromAddress("root", lldb.SBAddress(0x00007fff5fbff670, lldb.target), ptr_type)
>>> root.GetValue()
'0x000000de0000006f'
(which is probably the error you were making) makes sense too, because 0xde is 222 and 0x6f is 111 and I'm on a little-endian system...

I'm using SBValue's own CreateValueFromAddress method. It's not documented too well, but I've figured out the parameters and they are simpler than that of target's. Use it like so (no need for special address functions, just plain + operator):
offset_in_bytes = base_address + some_offset
some_other_sbvalue.CreateValueFromAddress("name-of-new-value", offset_in_bytes, value_type)

Related

gdb - how to call memset for the array of pointers

I debug an example program which defines the array of pointers:
int a = 1, b = 2, c = 3;
int* t[] = {&a, &b, &c};
I would like to set all pointers in the array to NULL during debugging. When I use the following command:
call memset(t, 0x0, sizeof(int*)*3)
I get this output:
$3 = (void *(*)(void *, int, size_t)) 0x7ffff77e7e10 <__memset_avx2_unaligned_erms>
When I print the array pointers are not set to NULL:
(gdb) print t
$4 = {0x7fffffffddc0, 0x7fffffffddc4, 0x7fffffffddc8}
What is wrong ?
I get this output:
You get this output because in your version of GLIBC memset is a GNU indirect function. It doesn't write any memory, it returns an address of the actual implementation (__memset_avx2_unaligned_erms in your case).
You can verify that this is the case:
$ readelf -Ws /lib64/libc.so.6 | grep ' memset'
1233: 00000000000b2df0 241 IFUNC GLOBAL DEFAULT 14 memset##GLIBC_2.2.5
557: 00000000000b2df0 241 FUNC LOCAL DEFAULT 14 memset_ifunc
6000: 00000000000b2df0 241 IFUNC GLOBAL DEFAULT 14 memset
To actually set the memory, you need to call the implementation function, such as __memset_avx2_unaligned_erms.
P.S. To memset an array of 3 pointers, it's easier to simply set each one individually: (gdb) t[0]=0. But I assume the object you actually want to zero out is larger.
For ease of debugging, you may write a trivial local_memset() and call it instead.
Building on Employed Russian's answer, insert () and use
call memset()(t, 0x0, sizeof(int*)*3)
That works because memset() returns the function you actually want to call.

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.

lldb and C code give different results for pow()

I have one variable, Npart which is an int and initialized to 64. Below is my code (test.c):
#include <math.h>
#include <stdio.h>
int Npart, N;
int main(){
Npart = 64;
N = (int) (pow(Npart/1., (1.0/3.0)));
printf("%d %d\n",Npart, N);
return 0;
};
which prints out 64 3, probably due to numerical precision issues. I compile it as follows:
gcc -g3 test.c -o test.x
If I try to debug using lldb, I try to calculate the value and print it in the command prompt, the following happens:
$ lldb ./test.x
(lldb) target create "./test.x"
Current executable set to './test.x' (x86_64).
(lldb) breakpoint set --file test.c --line 1
Breakpoint 1: where = test.x`main + 44 at test.c:8, address = 0x0000000100000f0c
(lldb) r
Process 20532 launched: './test.x' (x86_64)
Process 20532 stopped
* thread #1: tid = 0x5279e0, 0x0000000100000f0c test.x`main + 44 at test.c:8, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000f0c test.x`main + 44 at test.c:8
5
6 int main(){
7
-> 8 Npart = 64;
9
10 N = (int) (pow(Npart/1., (1.0/3.0)));
11 printf("%d %d\n",Npart, N);
(lldb) n
Process 20532 stopped
* thread #1: tid = 0x5279e0, 0x0000000100000f12 test.x`main + 50 at test.c:10, queue = 'com.apple.main-thread', stop reason = step over
frame #0: 0x0000000100000f12 test.x`main + 50 at test.c:10
7
8 Npart = 64;
9
-> 10 N = (int) (pow(Npart/1., (1.0/3.0)));
11 printf("%d %d\n",Npart, N);
12
13 return 0;
(lldb) n
Process 20532 stopped
* thread #1: tid = 0x5279e0, 0x0000000100000f4a test.x`main + 106 at test.c:11, queue = 'com.apple.main-thread', stop reason = step over
frame #0: 0x0000000100000f4a test.x`main + 106 at test.c:11
8 Npart = 64;
9
10 N = (int) (pow(Npart/1., (1.0/3.0)));
-> 11 printf("%d %d\n",Npart, N);
12
13 return 0;
14 };
(lldb) print Npart
(int) $0 = 64
(lldb) print (int)(pow(Npart/1.,(1.0/3.0)))
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
(int) $1 = 0
(lldb) print (int)(pow(64,1.0/3.0))
(int) $2 = 0
Why is lldb giving different results?
Edit: Clarified the question and provided a minimal verifiable example.
Your code calculates the cube root of 64, which should be 4.
The C code converts the return value to an integer by flooring it. The pow is usually implemented in some sort of Taylor polynomial or similar - this tends to be numerically inaccurate. The result on your computer seems to be a little less than 4.0, which when cast to int is truncated - the solution would be to use for example lround first instead:
N = lround(pow(Npart/1., (1.0/3.0)));
As for the lldb, the key is the text:
error: 'pow' has unknown return type; cast the call to its declared return type
i.e. it doesn't know the return type - thus the prototype - of the function. pow is declared as
double pow(double x, double y);
but since the only hint that lldb has about the return type is the cast you provided, lldb thinks the prototype is
int pow(int x, double y);
and that will lead into undefined behaviour - in practice, lldb thinks that the return value should be the int from the EAX register, hence 0 was printed, but the actual return value was in some floating point/SIMD register. Likewise, since the types of the arguments are not known either, you must not pass in an int.
Thus I guess you would get the proper value in the debugger with
print (double)(pow(64.0, 1.0/3.0))

How to call a function located in an executable from a loaded DLL?

I have located a function inside an executable which I'd like to call from my DLL. The address of it would be 0x0090DE00 according to OllyDbg. I've tried to call it directly:
luaL__openlib *f = ((luaL__openlib*)(module_handle + 0x0090DE00));
but also with adding the base of the module handle to it as suggested here:
uint8_t * module_handle = (uint8_t *)GetModuleHandle(L"ForgedAlliance1.exe");
luaL__openlib *f = ((luaL__openlib*)(module_handle + 0x0090DE00));
It appears that this is not working as I get access violation exceptions - it appears that the pointer is not valid.
So: How can I call this function by using its address?
I just inserted a simple RET instruction at 0x00C0B530. My code does now look as follows:
typedef void (*test) ();
EXTERN_DLL_EXPORT void initialize(lua_State *L)
{
// Adding this should not be necessary. I get 0x00C0B530 from
// OllyDbg where the offset 0x00401000 is included
uint8_t * module_handle = (uint8_t *)GetModuleHandle(L"ForgedAlliance1.exe");
test *f = NULL;
f = ((test*)(0x00C0B530));
(*f)(); // Crashing
}
What I don't quite understand is why I get a different address in the exception message:
Exception thrown at 0x909090C3 in ForgedAlliance1.exe: 0xC0000005: Access violation executing location 0x909090C3.
UPDATE: I just realized that 0x909090C3 is not just a pointer here, it is the code itself
90 | NOP
90 | NOP
90 | NOP
C3 | RETN
Seems I am messing something up with pointers. Why does it try to execute "location" 0x909090C3. That's not the location.
Alright, it was just a pointer mess-up. Sorry for that - did not write in C for quite a while. I did it right, basically, but the problem with
f = ((test*)(0x00C0B530));
(*f)();
is, that (*f) is 0x909090C3 - the instructions inside the executable - and this is the address the program tries to jump to which is of course invalid.
So the trick was:
int test_addr = 0x00C0B530
f = ((test*)(&test_addr ));
(*f)();
I am sure this can be done a bit simpler but this is working now.

uint8_t Array - Data inside memory

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

Resources