Understanding function calls in ARM ASM - android

I am disassemblying native Android libraries (armeabi-v7a) which were most likely created from C++ or C code and are stripped.
The target is to create a function call tree for later analysis.
I have issues understanding the disassembled output.
Take the following assembler snippet created by arm-linux-androideabi-objdump -d libledger.so > output.txt
00014988 <_ZSt10__pop_heapIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEENS0_5__ops15_Iter_less_iterEEvT_S9_S9_T0_>:
...
149e0: 4620 mov r0, r4
149e2: f030 fadd bl 44fa0 <_ZNK10__cxxabiv120__si_class_type_info11__do_upcastEPKNS_17__class_type_infoEPKvRNS1_15__upcast_resultE+0x2a7ec>
149e6: e7ff b.n 149e8 <_ZSt10__pop_heapIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEENS0_5__ops15_Iter_less_iterEEvT_S9_S9_T0_+0x60>
149e8: 4628 mov r0, r5
149ea: f030 fad9 bl 44fa0 <_ZNK10__cxxabiv120__si_class_type_info11__do_upcastEPKNS_17__class_type_infoEPKvRNS1_15__upcast_resultE+0x2a7ec>
149ee: f004 fe55 bl 1969c <__cxa_end_cleanup>
149f2: bf00 nop
149f4: b154 cbz r4, 14a0c <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_+0x14>
149f6: 0005 movs r5, r0
000149f8 <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_>:
149f8: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
149fc: 1d07 adds r7, r0, #4
149fe: b085 sub sp, #20
14a00: 4604 mov r4, r0
14a02: 4690 mov r8, r2
14a04: 460e mov r6, r1
14a06: 1b35 subs r5, r6, r4
14a08: 2d43 cmp r5, #67 ; 0x43
14a0a: f340 8095 ble.w 14b38 <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_+0x140>
14a0e: f1b8 0f00 cmp.w r8, #0
14a12: d13f bne.n 14a94 <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_+0x9c>
14a14: 10ad asrs r5, r5, #2
14a16: 4b4a ldr r3, [pc, #296] ; (14b40 <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_+0x148>)
14a18: 1eaf subs r7, r5, #2
14a1a: f10d 090c add.w r9, sp, #12
Of the branch instructions described here those of the BL family resemble most a function call, which is also hinted at 5.3 Subroutine Call.
Then there are also system calls via SWI.
Yet some questions arise to me:
Can I be sure for the BL instructions that the labels to jump to always point to the beginning of a C-function? This would mean that they act like calling a C-function.
What other instructions are used for C-function calls?
In the example above it would mean at 149e2: there is a function call. I don't understand the <XY+0x2a7ec> part though.
Does that mean that ...
The called function starts at addressoff(XY) + 0x2a7ec, but is not in the .dynsym table and thus has no human-friendly name for the disassembler to refer to?
Does it mean that XY is called with a huge offset into its body?
Or are both possible?
How do I recognise the start of functions? To me it looks like the parts with complete addresses like 00014988 <...> are functions. Though I fear that this only works for functions that are part of the dynamic symbols table, which would explain the huge offsets above.
At 149f4 there also is a branch, this time via CBZ. This also looks like a function call into a different function, and again with an offset. When both 00014988 and 000149f8 are functions when this CBZ call would jump directly into the function and not at the beginning. What does this mean?

Can I be sure for the BL instructions that the labels to jump to always point to the beginning of a C-function? This would mean that they act like calling a C-function.
Yes, most of the time the branch will be to the beginning of the function.
What other instructions are used for C-function calls?
Anything that can change the program counter.
I've see BX, LDR PC, and POP instructions.
In the example above it would mean at 149e2: there is a function call. I don't understand the part though. Does that mean that ...
The called function starts at addressoff(XY) + 0x2a7ec, but is not in the .dynsym table and thus has no human-friendly name for the disassembler to refer to?
Not every address aligns with a sourced line number. The offset is the distance from a known symbol in the map file, usually a function name.
Does it mean that XY is called with a huge offset into its body?
No. The destination of the branch is at an offset from a public symbol. There are many cases where a lot of functions are not public, so they are referenced to the nearest public symbol in the map file.
Or are both possible?
See above.
How do I recognise the start of functions?
There is no general rule.
Here is a process:
Open up the listing file (that contains the assembly language).
Look for the offset within the assembly language listing.
Or find the fundtion, then add the offset and look for that address.
At 149f4 there also is a branch, this time via CBZ. This also looks like a function call into a different function, and again with an offset. When both 00014988 and 000149f8 are functions when this CBZ call would jump directly into the function and not at the beginning. What does this mean?
The CBZ is not a subroutine or function call. It is a branch to another address. No return is expected.
The Branch and Link (BL) and Branch and Exchange (BX) instructions set the LR register to a return address (usually the next instruction after BL or BX). In order to return, the value in the LR register is copied into the Program Counter (PC) register, causing execution to transfer to the address in LR. This is a return from the function or subroutine call.

Related

ARM64 hooking: insert a jump in memory

I'm trying to hook on a 64 bit ARM Android device the SSL_do_handshake function available in libssl.so, until now I have:
address of libssl.so (found in proc//maps)
offset of SSL_do_handshake(found in libssl.so)
absolute address of SSL_do_handshake (address_of_libssl + offset_of_SSL_do_handshake)
What I'm doing is save the instructions at absolute address of libssl.so (for recovery) and overwrite them with my instructions (for jump):
LDR X9,#8
Br X9
address for jump 7f75a5b890
In detail what I'm saving in memory is 49000058 20011fd6 90b8a5757f if I look in memory after the overwriting I found my instructions and the address. If I try to execute it and call SSL_do_hanshake I have a crash before the jump.
I did the same for ARMv7 using thumb32 with the same approach but different instructions:
ldr pc [pc,#0]
address for jump (f36e240d)
In memory dff800f0 0d246ef3 and it works.
Any idea of what I'm doing wrong?

Sometimes gcc would put the first argument into R1 register when compiling the C++ code for arm abi? [duplicate]

This question already has an answer here:
the order of C++ implicit arguments: this and the returned object, which goes first?
(1 answer)
Closed 7 years ago.
From the ARM to C calling convention, I know that the arguments are passed in order starting from registers r0-r4 and then for other arguments stacks are used. Return values are passed to r0-r1.
But in the libart.so (AndroidM, /system/lib/libart.so, 32bit), there is a method seems like doesn't match the rule.
//https://android.googlesource.com/platform/art/+/android-6.0.0_r5/runtime/oat_file.cc
std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
return DexFile::Open(dex_file_pointer_, FileSize(), dex_file_location_,
dex_file_location_checksum_, this, error_msg);
}
//https://android.googlesource.com/platform/art/+/android-6.0.0_r5/runtime/dex_file.h
static std::unique_ptr<const DexFile> DexFile::Open(const uint8_t* base, size_t size,
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
std::string* error_msg) {
return OpenMemory(base, size, location, location_checksum, nullptr, oat_dex_file, error_msg);
}
The OpenDexfile is a memeber function of the OatDexFile class which is a inner class of OatFile class. So the OpenDexFile has 2 arguments actually, as the first argument is "this".
But in the IDA Pro, the OpenDexFile looks like below:
.text:002E9718 var_14 = -0x14
.text:002E9718 var_4 = -4
.text:002E9718
.text:002E9718 STR.W R4, [SP,#var_14]!
.text:002E971C MOV R4, R1 ;<<--After analysing, I can assure that R1 is the "this" pointer
.text:002E971E LDR R1, [R1,#0x20] ;<<---dex_file_pointer
.text:002E9720 STRD.W R5, R6, [SP,#4]
.text:002E9724 ADDS R3, R4, #4
.text:002E9726 MOV R5, R0 ;<<---It seems like that r0 is added but not for the "this" pointer
.text:002E9728 STRD.W R7, LR, [SP,#0xC]
.text:002E972C LDR.W LR, [R4,#0x1C]
.text:002E9730 SUB SP, SP, #0x14
.text:002E9732 MOVS R7, #0
.text:002E9734 LDR R6, [R1,#0x20]
.text:002E9736 STRD.W R4, R2, [SP,#8] ;<<--R2 represent the arg "error_msg"
.text:002E973A STRD.W LR, R7, [SP]
.text:002E973E MOV R2, R6
.text:002E9740 BL DexFile::OpenMemory ;<<---DexFile::Open is a inline function. When executing this instruction, r0 equals r5.
.text:002E9744 MOV R0, R5;<<--OpenMemory is also a bit weird. It looks like that OpenMemory also adds r0 for the return value, because r0 equals r5 before calling OpenMemory
.text:002E9746 ADD SP, SP, #0x14
.text:002E9748 LDRD.W R4, R5, [SP]
.text:002E974C LDRD.W R6, R7, [SP,#8]
.text:002E9750 ADD SP, SP, #0x10
.text:002E9752 LDR.W PC, [SP+4+var_4],#4
I am just wondering if there is a special situation in which "this" pointer would be put into R1 but not R0 and the argments are passed in order starting from registers r1.
I will be appreciated if you can help me.
From Procedure Call Standard
If the subroutine is a function that returns a result in memory, then
the address for the result is placed in r0 and the NCRN is set to r1.
OpenDexFile
is (probably) returning a DexFile object which requires a memory to be put, so that's r0 and r1 becomes this.
This has been talked about before: the order of C++ implicit arguments: this and the returned object, which goes first?
General note is ARM ABIs are similar to Itanium ABIs. If you have a problem finding source to study after checking ARM ABIs, you can look into that one as well.
Check arm ABI chapter 5.5
R0: for return value
R1-R3 plus stack: for passing arguments

Arm Instructions [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
i wanted to ask what is happening in arm instruction here. I have knowledge of ASM but i am having hard time understanding ARM. I try to look up the info on the internet that gives the basics but the thing i am looking at is a little different. So here is a code i am trying to understand.. Can you please explain what these instructions are doing. I will mark the ones i dont understand. Its a code from IDA. Can someone please explain the entire function. i will really be grateful. Thanks
LDR R3, =(unk_E9BFB0 - 0x6B1B4C) //This once,i dont get it, is it subtracting?
LDR R8, [R5]
MOV R1, R6
ADD R3, PC, R3
LDR LR, [R4,#0xC] //This instruction
LDR R12, =(aDraw_debug - 0x6B1B68) //This once
MOV R2, R7
STR R8, [R3,#0x30]
MOV R0, R3
STR R4, [R3]
ADD R12, PC, R12 ; "draw_debug" //This once
STR R3, [R5]
STR R12, [R3,#0x2C]
ADD R12, LR, #1
STR R12, [R4,#0xC]
BL __aeabi_atexit
LDR is the instruction on ARM to load a register with a value from memory. The following, however, are the pseudoinstruction form of LDR:
LDR R3, =(unk_E9BFB0 - 0x6B1B4C) //This once,i dont get it, is it subtracting?
LDR R12, =(aDraw_debug - 0x6B1B68) //This once
I believe it is constructing an offset from a code location to pull data out of the .text section. aDraw_debug - 0x6B1B68, for example, is likely taking the address of label aDraw_debug, and subtracting the location of some instruction, 0x6B1B68.
The end result is that this essentially will load the offset of aDraw_debug (from an arbitrary point) into R12. Likewise, the other instruction will load unk_E9BFB0 into R3. That one is probably compiler-generated data because of the mangled name.
The other LDR instruction:
LDR LR, [R4,#0xC] //This instruction
are a straightforward affair. LDR is still being used to load a register from memory, but the addressing is different. In this case, LR, the link register, is being loaded with the data at address R4 + 0xC in memory.
The ADD is straightforward as well, and I'm not sure if your were confused as to what it was doing but:
ADD R12, PC, R12 ; "draw_debug" //This once
this simply adds PC + R12 and stores it in R12 without updating the processor flags. This takes the offset determined earlier and applies it to the current PC.
Overall, it looks like this is code to store values into some sort of struct or class. The compiler chose to do PC-relative addressing, but the offset is likely outside of the usable range for the instruction. PC-relative LDR/STR instructions can only address +/- 4096 from PC.
The ldr reg,=something is a shortcut. The arm is a mostly fixed length instruction set or lets say there are not enough bits to allow for any possible immediate value. Also this shortcut allows you to use labels, load the address of some label into this register. What the assembler does with this is when it generates the machine code it allocates a word location somewhere not too far away that is not in the execution path (after an unconditional branch or bx for example). Then for the ldr reg,= instruction it encodes a pc relative instruction ldr reg,[pc,+offset] to load that value into the register. This allows for any 32 bit value to be loaded, no restrictions. It also allows for labels to be used where the data value (address) is filled in later by the linker. Your example takes that one further and does math on a label, so the assembler or linker will have to resolve the label, do the math, then put that value in the word location.
ARM.COM Arm instruction Set
Info Center of ARM.com - Quick Reference Cards for ARM instruction set
Doc for ARM instruction set
Indexed for each instruction web page
Arm-instructionset
Embedded Systems Architecture: The ARM Instruction Set Architecture by Mark McDermott With help from ourgood friends at ARM

BX LR and ARM return from exception instructions (RFE and ERET)

In ARM architecture, returning from exception can be done in two ways which I know,(there might be others). But main logic is to modify PC, which will make processor trigger into mode set in CPSR.
So pop {...,pc} would make a switch to say user from supervisor
or mov pc,lr would do the same.
My Question is, would a BX lr make the switch ?
Assuming I am handling IRQ and I call a assembly routine say do_IRQ and then return from do_IRQ is via BX LR. Would this make the code after bl do_IRQ in my fault handler irrelevant ?
irq_fault_handler:
push {lr}
push {ro-r12}
mrs r0, spsr
push {r0}
bl do_IRQ
pop {r0}
msr cpsr, r0
pop {r0,-r12}
pop {lr}
subs pc, lr, #4
do_IRQ:
...
BX LR
It does not make it irrelevant since you called do_IRQ with bl instead of just a branch so you've already overwritten lr. Furthermore, even if you just did a branch, your stack would be messed up (you push r0-r12 but never pop them before returning).
Also, the code you show doesn't seem to return from the exception correctly either. Most of the time, when you return from an exception, you want to restore the program status registers as well as the registers which a mov pc, lr won't do nor will a bx lr.
Furthermore, the address contained in lr will actually be offsetted by a few words (it varies depending on the type of exception) so you're not returning to the correct instruction anyway. For IRQ, I believe it is off by 1 word.
The recommended way to return from an IRQ exception is a subs pc, lr, #4 instruction (after you've pop'd all your registers beforehand of course) which is special in that it also restores the CPSR.

No refrence for instructions strneh, lsreq, streqb

I was looking at strcpy.S file in android platform at path libc/arch-arm/bionic, in this file there are many arm instructions which i am not able to understand, i am also referring ARM System Developers Guide.
Here except "tst" and "tstne" i am not able to find any refrence for others in any book or ARM refrence manual.
tst r2, #0xff00
iteet ne
strneh r2, [ip], #2
lsreq r2, r2, #8
r2, [ip]
tstne r2, #0xff
Not only these instructions there are many others in different files also.
Does anyone have any idea what these instructions are ?
The first instructions it the it-instruction from the thumb instructions set.
iteet ne
This instruction marks the next three instructions to be conditional executable. The last three characters of the instruction make a pattern consisting of e (else) or t (then). The operand 'ne' specifies the condition to be evaluated.
The other three instructions are ordinary ARM instructions with conditionals:
strneh r2, [ip], #2 ; store halfword if not equal
lsreq r2, r2, #8 ; logical shift right if equal
tstne r2, #0xff ; test if not equal
These are the three instructions affected by the it-instruction. They come with ne/eq conditional flags as well.
As you can see the conditions of the it-instructions and the conditions of the other three instructions are in conflict to each other. This is a bug in the code. Most likely it hasn't been discovered before because the code-snippet is from the ARM-big-endian code, and I know of no android phone that uses ARM in big endian.
Btw, it's worthwhile to know why the conditions are given in the it-instruction and in the instructions itself. This is part of the unified arm assembly standard. On the ARM you have two modes of operation: Thumb mode (uses It-instruction, less powerful) and ARM-mode (more powerful, uses condition-flags in the instructions itself).
If you limit yourself to the capabilities of the thumb-mode it is possible to write code that would compile in thumb and ARM-mode. This is done here.
If you assemble for Thumb-mode the It-instruction will be used to control the conditions of the next three instruction, and the conditions within the instructions gets ignored. If you assemble to ARM-instruction set the It-instruction gets ignored and the conditions from the instruction itself will become active.
This works well as long as the it-instruction and the conditions in the arm-instructions match. As I said before this is not the case here, so it will either not work in thumb-mode, arm-mode or both :-)
strneh is a store command with some conditional execution/size specifier suffixes. The ARM docs are a good place to start: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0068b/Chdehgih.html
If you google "arm conditional execution", you'll find a number of blogs/articles that may also help: http://blogs.arm.com/software-enablement/258-condition-codes-2-conditional-execution/
As for your *strneh" instruction:
str = store
ne = execute if not equal (Z flag clear)
h = perform a half-word operation

Categories

Resources