So I'm currently trying to understand how an Android app interprets the data sent from a Bluetooth-enabled scale.

Understanding the Java code was relatively easy. The code was obfuscated but I found out how the Bluetooth protocol works.

However, the app use the Android NDK to call a native (armeabi) library that calculates data like body fat percentage from the data sent from the scale (weight, impedance...): libBodyfat.so

I know what all the parameters are and what the C-functions return, but I don't know how they do it (what calculations are done).

Apparently it's not possible to create readable code from a C library the way it's possible with Java. I found some tools that were recommended to work with C binaries (e.g. IDA) but they don't work with ARM binaries.

What can I do to understand how the library works?

  • By readable C code are you referring to comprehensive C commands such as printf(), or are you referring to obfuscated ARM assembly output? Edit: noticed you wrote "the way it's possible with Java" and thus I believe that you're referring to C source code ouptut. Jun 24, 2018 at 4:11
  • Any disassembler that supports the ARM for which the code was built, will be able to give you a readable representation. However, it takes more effort to make sense of these mnemonics produced by a disassembler than of C pseudo code. There are also free (of charge) and affordable decompilers for hobbyists which support ARM and produce pseudo code. Your question is right at the heart of what reverse code engineering is about.
    – 0xC0000022L
    Jun 24, 2018 at 20:29
  • Can you recommend some free ARM decompiler?
    – akichii
    Jun 24, 2018 at 20:42
  • You can find online decompilation service at retdec.com (it is able to decompile 32 bit arm and as far as I can tell from your mentions of armeabi it should fit). It is open source and its sources are here : github.com/avast-tl/retdec
    – w s
    Jun 26, 2018 at 8:06

2 Answers 2


Hope it is not too late. I will try to help you on this. I've been go through this and that to reverse engineer that exactly same library. libBodyfat.so. As @TheKalin answered, you will find few .so files in the folder.

I found x86-64 is the easiest to read compare to others. Here are the tools that I used to reverse engineer the library:

  1. IDA-free. It will list the constant value nicely.
  2. HopperApp. I used it for disassemble and decompile to c-like language. It also able to disassemble ARM. You can try the demo version, but it will close the app for sometimes and you need to re-open it.
  3. Hex to Float Convt.. Some constant values are used in the formula, I converted those values with this website.
  4. And websites to learn how the assembly instructions work.

I manage to convert some of the functions (init & body fat percentage) to javascript functions

Here it is. I have not clean up the code yet. And please do let me know if there is mistakes or something that I need to improve.


Hope it is helpful.

  • Wow, that's impressive! I couldn't even find out how to open the binary in IDA free. I'll test your implementation against the libBodyfat.so and report back later.
    – akichii
    Jul 25, 2018 at 9:50
  • sure. let me know if the result is incorrect or does not match with the library or there is something need to be improved. thanks! Jul 25, 2018 at 16:39
  • I think we were actually working on two different libraries. I looked at a library that exports the com.holtek.libHTBodyfat namespace included in "Mi Fit". However, I will try to follow your steps since it seems to work nicely in this case and report back if I succeed.
    – akichii
    Jul 25, 2018 at 19:53

Reverse engineering of .so file is not an easy task. C is not like java, where you can turn .class files into more readable forms like .smali.

You can use radare2 to inspect .so file, however to get anything from the r2 output you need some basic knowledge on processor architecture and proper opcodes.

You can begin your education here : https://azeria-labs.com/writing-arm-assembly-part-1/

Or you can find some basic instructions below:

Lets assume that you have radare2 installed and you have already unziped your apk file.

Go to the apk directory and list the lib directory abi docs:

$  tree lib
├── arm64-v8a
│   └── libnative-lib.so
├── armeabi-v7a
│   └── libnative-lib.so
├── x86
│   └── libnative-lib.so
└── x86_64
    └── libnative-lib.so

4 directories, 4 files

Select your platform (for your case it will be armeabi-v7a or arm64-v8a)

Open it with ( -A option runs aaa command )

 r2 -A lib/armeabi-v7a/libnative-lib.so

List the functions or search the specific function name

    [0x00006498]> afl
    [0x00006498]> afl ~JNI
    0x000064e4    9 256  -> 238  sym.Java_foo_com_bar_MainActivity_stringFromJNI
    0x000065f0    1 44           sym._JNIEnv::NewStringUTF_charconst
    0x00006724    1 28           sym.JNI_OnLoad
    //Jump to the function:
    $ [0x00006498]> s 0x00006724
    //print the instructions
    $ [0x00006724]> pdf 
/ (fcn) sym.JNI_OnLoad 28
|   sym.JNI_OnLoad ();
|           ; var int local_0h @ sp+0x0
|           ; var int local_4h @ sp+0x4
|           ; var int local_8h @ sp+0x8
|           ; var int local_ch @ sp+0xc
|           ; var int local_10h @ sp+0x10
|           ; UNKNOWN XREF from 0x00000234 (aav.0x00000224 + 16)
|           0x00006724      85b0           sub sp, 0x14
|           0x00006726      0a46           mov r2, r1
|           0x00006728      0346           mov r3, r0
|           0x0000672a      0490           str r0, [sp + local_10h]
|           0x0000672c      0391           str r1, [sp + local_ch]
|           0x0000672e      0620           movs r0, 6                  ; aav.0x00000006
|           0x00006730      .dword 0x0001f2c0 ; aav.0x0001f2c0
|           0x00006734      0290           str r0, [sp + local_8h]
|           0x00006736      0298           ldr r0, [sp + local_8h]
|           0x00006738      0192           str r2, [sp + local_4h]
|           0x0000673a      0093           str r3, [sp]
|           0x0000673c      05b0           add sp, 0x14
\           0x0000673e      7047           bx lr

Now you have to interpret the radare2 output, to do this you need the op codes list with description, it can be found here or (for arm64) here.

As you can see there is no easy way.

TIP You can tell radare2 to write opcodes description next to them. Just type

e asm.describe=1

and the output will change to something like this:

|           0x0000672e      0620           movs r0, 6                  ; aav.0x00000006 ; move immediate into register and update flags
|           0x00006730      .dword 0x0001f2c0 ; aav.0x0001f2c0         ; write 16 bit value on top of halfword
|           0x00006734      0290           str r0, [sp + local_8h]     ; store register into memory
|           0x00006736      0298           ldr r0, [sp + local_8h]     ; load from memory to register
|           0x00006738      0192           str r2, [sp + local_4h]     ; store register into memory
|           0x0000673a      0093           str r3, [sp]                ; store register into memory

Final note:

Arm libraries sometimes use Thumb mode, and this is the topic for another time. You can find some info about thumb mode on azeria-labs webiste

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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