A, goals,
When doing code restoration, we often see some strange registers and strange instructions:
vldr s15, [r1]
vadd.f32 s15, s14, s15
Copy the code
Very much like some flow star, look very familiar, look carefully and do not know.
They are known as floating point operations, and today we light up a very useful skill tree: Unidbg debugging floating point operations
Second, the steps
Write a floatdemo first
There’s a little bit of a heirlooms.
extern "C" JNIEXPORT jstring JNICALL Java_com_fenfei_app_floatdemo_MainActivity_stringFromJNI( JNIEnv* env, jobject Obj, jdouble value) { std::string hello = "Hello from C++"; Double p = 3.14159; double s,v,rc; v = 2*p*value; s = p*value*value; rc = v+s; hello = std::to_string(rc); return env->NewStringUTF(hello.c_str()); }Copy the code
Figure out the circumference and the area of the circle and then add them up.
High level language is good, clear.
IDA, a
There are two differences, one is the register is different, ordinary operation uses register r0-rx, floating point operation uses register d0-dx (in fact, there are also s0-sx), the other is the instruction is different, ordinary operation uses register MOV, MUL, while floating point operation uses VMOV, VMUL. It feels like a VIP version of normal computing.
The first knowledge point comes out, the instruction at the beginning of V is the floating point operation instruction, Dx Sx Qx is the floating point register.
Unidbg appearance
This framework runs floatDemo. apk we just compiled, and then adds a stringFromJNI function call.
private String callfun(String methodSign, Object ... args) { DvmObject mainactivity = MainActivity_dvmclass.newObject(null); Object value = mainactivity.callJniMethodObject(emulator,methodSign,args).getValue(); return value.toString(); }Copy the code
Since stringFromJNI is not a static class function, we need to create a MainActivity object before we can call its methods.
Run first to see the results
Find native function Java_com_fenfei_app_floatdemo_MainActivity_stringFromJNI(D)Ljava/lang/String; => RX@0x4000c6c9[libnative- lib-so] 0xC6C9 JNIEnv->NewStringUTF("150.796320") was called from RX @ 0 x4000c73d [libnative - lib. So] 0 xc73d ret: 150.796320 emulator destroy...Copy the code
We pass a circle with parameter 6, radius 6, circumference 37.699, area 113.097, and their sum is 150.796. It turned out to be fine, so let’s start debugging.
Unidbg debugging
We know from the result we just ran that the stringFromJNI function is at 0xc6c9, so now we need to put a breakpoint at that address and have the debugger stop at that address.
Unidbg’s debugging capabilities are still strong. It supports three debugging modes: CONSOLE, GDB, and IDA. For now, I’m comfortable with CONSOLE.
Open debug fried chicken simple, add these two lines of code line
Debugger MyDbg = emulator.attach(DebuggerType.CONSOLE);
MyDbg.addBreakPoint(module.base + 0xc6c9);
Copy the code
After running this command, you will successfully enter the debugger command line. Press enter to display the currently supported debugging commands.
We are beginners, so we need to master two commands: n and S. N is a single step, which means to execute an instruction and step through a function call. S is to step in, which is to execute an instruction into a function call.
The n command runs a few times down to the position of the floating-point arithmetic we want to analyze.
The Unidbg debugger only shows the Rx registers, not the Dx series registers.
Open the Unidbg floating point register display
Unidbg supports floating point simulation, so there must be a place to read the floating point register, it’s just not displayed.
Let’s first analyze the register display part of Unidbg debugging code.
So I’m going to search for r0= first where was it processed?
ShowRegs displays registers. If the parameter is null, all registers are displayed using ARM. GetAllRegisters. But why aren’t floating point registers displayed? Strange.
Scrolling down, we find that the ARM64 simulation shows registers Q0-Q31. By looking up the data, we know that they are all in the same group.
Let’s put the ARM32 in, and let’s switch the simulation to ARM64
emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("com.fenfei.runfloatdemo").build(); // Create an emulator instance that emulates either 32-bit or 64-bitCopy the code
Run again, debugger not activated?
Why is that? We switched from Arm32 to Arm64, so we loaded 64-bit so, so we changed the address of stringFromJNI, we need to set the breakpoint at the new address 0x12738.
Now this is different. The floating point registers are displayed.
Optimize the display of floating point registers
Li boss: fenfei ah, this 0x400921F9F01B866e is what meaning ah, you are wrong, floating point number register display how is not 3.14159, but this messy data?
Fenfei: boss, the mother language of programmer is 16 enter system, have not one eye 0x400921F9F01B866E recognize is 3.14159 of, the dinner is unworthy to add chicken leg of, also unworthy to change bald of.
There are ideal students please search IEEE754 binary floating point arithmetic standard
Other students please join me to optimize the display of floating point registers.
As feige so far has not become bald, indeed can not see that this thing is 3.14159, had to find another way to teach you a magic function:
public static double bytes2Double(byte[] arr) { long value = 0; for (int i = 0; i < 8; i++) { value |= ((long) (arr[i] & 0xff)) << (8 * i); } return Double.longBitsToDouble(value); Case Arm64Const.UC_ARM64_REG_Q0: byte[] data = backend.reg_read_vector(reg); double bOut = bytes2Double(data); if (data ! = null) { builder.append("\n>>>"); builder.append(String.format(Locale.US, " q0=0x%s(%.3f)", newBigInteger(data).toString(16),bOut)); } break;Copy the code
Science says we can still get stronger without going bald.
In fact, C/C++ has a magic thing called a pointer, which shows a shuttle
BYTE dPiByte[8] = {0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40 };
double dPi = *(double*)dPiByte;
Copy the code
Good, the following several steps operation is multiply multiply add add, the classmate yourself n a few ok.
(Applause)
Third, summary
Why to debug, direct F5 method does not smell good?
Now Ollvm is rampant, master some manual tear compilation can protect you worry-free.
Why use Unidbg to debug, IDA doesn’t smell good?
Wukong, waiting for You to encounter the memory to prevent modification, unable to set software breakpoints and some BT anti-debugging, You will come back and sing this song for the division: Only You……
For the preview, the next article is to enable the display of floating point register and TraceCode under Arm32
Do you know why beauties always die? Because no one cares how long ugly people live.
TIP: The purpose of this article is only one is learning more backward techniques and train of thought, if anyone use this technology to get illegal commercial interests the legal liabilities are their operators, and the author and it doesn’t matter, this paper involves the knowledge of code project can go to my friends to fly star come undone, welcome to join star learn together to explore technology knowledge. Questions can be added to me WX: Fenfei331 discussion.
Wechat public account: Fenfei security, the latest technology dry goods real-time push