blob: 692a878486c1b5b894594c7a60924094334c3a38 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
# call primitive
4-arg call primitive (fast b0i) works like this:
- backup `atan2` lazy symbol address
- take 4 32-bit args and pack them into 2 doubles. 1 double (64-bits) is passed as 2 registers (32-bits), thus giving us 4 32-bit args.
- overwrite `atan2` lazy symbol address with addy to call (used by `Math.atan2`)
- call `Math.atan2` with args, get ret val from same function
- replace `atan2` lazy symbol address with its real value
- return ret val
26-arg call primitive (slower b0i) works like this:
- overwrite lazy symbol address for __stack_chk_fail (doesn't specifically need to be that function, i just use it as it shouldn't be called in normal operation anyway), with its own resolver, so calling it will just spin.
- create a new pthread running __stack_chk_fail's resolver, so it spins indefinitely
- get the mach thread port thing for that pthread, for later
- suspend the thread
- allocate some memory for the mach thread state
- allocate some memory for a fake stack
- write first 4 arguments to r0-r3 in the thread state itself
- place the rest of the args on the fake stack, and set the stack ptr to point to the fake stack
- set return address (lr) to a ROP gadget that adds 0x3c to the stack, and pops a bunch of reg's (more args)
- write pthread_exit to fake stack + 0x58, where the pc will be popped from
- run pthread_join
- wait
- pthread_exit exits the thread, r0 contains the function we called's return value, which will be grabbed by pthread_join
- pthread_join writes the ret val to a known location, which we then read the return value from
- return the ret val
|