1

I am trying to figure out how to solve the following. I have two ARM .SO libraries (32 bit and 64 bit) with the same functions. There is a method which returns const char* , it looks like this in ARM32:

.text:0006F264                 PUSH            {LR}
.text:0006F266                 SUB             SP, SP, #0xC
.text:0006F268                 STR             R0, [SP,#0x10+var_C]
.text:0006F26A                 LDR             R3, =(dword_9A030 - 0x6F270)
.text:0006F26C                 ADD             R3, PC  ; dword_9A030
.text:0006F26E                 LDR.W           R3, [R3,#(dword_9A250 - 0x9A030)]
.text:0006F272                 LDR             R0, [SP,#0x10+var_C]
.text:0006F274                 BLX             R3
.text:0006F276                 MOV             R3, R0
.text:0006F278                 NOP
.text:0006F27A                 MOV             R0, R3
.text:0006F27C                 ADD             SP, SP, #0xC
.text:0006F27E                 LDR.W           PC, [SP+4+var_4],#4

And here in ARM64:

.text:0000000000079CAC                 SUB             SP, SP, #0x20
.text:0000000000079CB0                 STR             X30, [SP,#0x20+var_20]
.text:0000000000079CB4                 STR             X0, [SP,#0x20+var_8]
.text:0000000000079CB8                 ADRP            X0, #dword_DE080@PAGE
.text:0000000000079CBC                 ADD             X0, X0, #dword_DE080@PAGEOFF
.text:0000000000079CC0                 LDR             X1, [X0,#(qword_DE4C0 - 0xDE080)]
.text:0000000000079CC4                 LDR             X0, [SP,#0x20+var_8]
.text:0000000000079CC8                 BLR             X1
.text:0000000000079CCC                 NOP
.text:0000000000079CD0                 LDR             X30, [SP,#0x20+var_20]
.text:0000000000079CD4                 ADD             SP, SP, #0x20
.text:0000000000079CD8                 RET

This is the ASM code of a function

const char* GetStatus ( const DetailsHandle obj )

This function can return one of 3 string values "abcd", "kowewqzb", or "jvbrnbfghert" (as char*). I want it to return always "kowewqzb" regardless of the call happening within this function, which leads to an entire bunch of dynamically loaded functions. So how could I:

1) write the code for making it always return the address of "kowewqzb" (which needs to be put somewhere into memory first) and don't do any other calls (so basically the entire instruction set besides of SP manipulations could be replaced with other instructions

2) if there is not enough space for making it work directly there, how could I inject some new code without destroying existing code, are there any suitable places for that in the .SO library? E.g. putting BL to some unused areas (how to get them?) and having there further code pieces.

Ideally if this could be outlined for both ARM32 and ARM64 I'd be more than happy. Huge thanks in advance!!!

1 Answer 1

2

As I understand, you want to replace the function with code such that it returns a pointer to the ASCII string "kowewqzb".

Since the function in question is quite long you have sufficient space to write an inline patch both for ARM32 and ARM64.

For ARM32, you can use the following piece of code

.global main
.text
.thumb_func

main:
adr r0, str
bx lr

str:
.asciz "kowewqzb"

Note that this is 16-bit Thumb code instead of 32-bit ARM as even the disassembly you posted uses Thumb instructions. After assembling and objdump this yields

$ arm-linux-gnueabi-objdump -d arm32.o

arm32.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <main>:
   0:   a000        add r0, pc, #0  ; (adr r0, 4 <str>)
   2:   4770        bx  lr

00000004 <str>:
   4:   65776f6b    .word   0x65776f6b
   8:   627a7177    .word   0x627a7177

For ARM64,

.global main
.text    
main:
adr x0, str
ret

str:
.asciz "kowewqzb"

which yields

$ aarch64-linux-gnu-objdump -d aarch64.o

aarch64.o:     file format elf64-littleaarch64


Disassembly of section .text:

0000000000000000 <main>:
   0:   10000040        adr     x0, 8 <str>
   4:   d65f03c0        ret

0000000000000008 <str>:
   8:   65776f6b        .word   0x65776f6b
   c:   627a7177        .word   0x627a7177

And finally, be sure to add a zero byte at the end to make it a proper null terminated ASCII string.


EDIT:

As said below in the comments you do not need to edit .rodata or any other section in the binary. The string is included as a part of the code bytes with which you are going to overwrite the GetStatus function.

For example, for ARM 32,

main:
adr r0, str
bx lr

str:
.asciz "kowewqzb"

The adr r0, str instruction loads the address of string which is immediately located after it. The adr instruction is actually a pseudo-instruction and assembles to add r0, pc, #0. It calculates the address of the string by adding 0 to the current Program Counter (PC). In ARM, the PC always points to two instructions ahead of the currently executing instruction. That's why we add 0 since it already points to str when executing the adr r0, str instruction.

Obtaining the address of the string this way is called PC relative addressing. This makes it possible to avoid hard coding the address of the string in the patched code.

You can use this online arm assembler to see the bytes corresponding to the instructions.

enter image description here

You need to overwrite the function with the bytes shown on the left panel. No other modifications are necessary.

9
  • Many thanks for your reply! But the problem here is that there is no predefined "kowewqzb" string and I need to modify an existing .so file. What would you recommend? Just modify any unimportant string there to become this string and set the pointer to it? Are there any more elegant solutions? E.g. by creating this string on the fly and returning it? Thank you! P.S. Obviously I don't have an access to the source code, just using IDA Pro on it. Jun 13, 2019 at 20:57
  • @ARMResearcher The string is included in the assembly code itself (str). It uses PC relative addressing to access it. You just have to overwrite function with the assembled bytes (like a0 00 47 70 65 77 6f 6b 62 7a 71 77 for ARM32).
    – 0xec
    Jun 13, 2019 at 21:39
  • I have now modified a string in a .rodata section, changing to the string I wanted (it was just some kind of an informational text, which I can safely ignore for my purposes), now I put in IDA Pro the following code for ARM32 thumb: LDR r0, =0x0008BD4C; BX lr Is it correct or do I need to add: ADD R0, PC before leaving the function? I am not sure if I need to add the PC value here. Thank you!!! Jun 13, 2019 at 22:03
  • @ARMResearcher You cannot hardcode the address like that. It depends on where the .so will be loaded.
    – 0xec
    Jun 14, 2019 at 6:09
  • @ARMResearcher Also you are not getting the point of my answer. You don't have to edit .rodata or any other section. The string is included in the patched bytes after the adr r0, str; bx lr instructions.
    – 0xec
    Jun 14, 2019 at 6:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.