原创文章,转载请注明: 转载自All-iPad.net 本文链接地址: 如何用gdb找到Android so文件中的加密key
来自XDA developer的一篇文章,作者详细描述了如何使用gdb + ida找到Angry Birds RIO Android版中lua文件的加密key,虽然目前还不会反向工程,不过说不定哪一天会用上,先记录下来。
Well… I have attached a debugger to native code, set breakpoints, analyzed registers, memory, etc. It wasn’t that easy though. It took me several days to start debugging and get first key, but I got second one in about 1 hour.
Actually I don’t really need that key, I can’t even play Angry Birds Rio on my old G1, but it was challenging and I love challenges Plus I have learnt a LOT about gdb, assembler, ARM architecture, etc.
So I want to thank you, Goddchen, for giving me an opportunity to learn & play
Ok, let’s move on…
First, I have disassembled libangrybirds.so using IDA Pro 5.5 . I was able to examine code and attach IDA to gdbserver on a device, but unfortunately it wasn’t working properly. IDA was thinking that libangrybirds.so is a main binary of a process it attached to, but it should look into loaded shared libs instead. Weird, but I didn’t find a way to attach it properly. And this is pity, because IDA is a great tool and it would make debugging a pleasure, but I had to use gdb instead.
Second, Android has problems with debugging multi-threaded native code. MT support was added in NDK r5 and because of some bug it’s not possible on a system older than Gingerbread.
Third, you could attach gdb manually, but ndk-gdb script does great work for you. You will have to do some tricks to use it with 3rd party app though.
Fourth, it seems libangrybirds.so is a Java code compiled to native or something like that. There are objects like FileInputStream, ByteOutputStream, etc., but there are also some API differencies. We’ll see String and Array<uchar> objects, but it’s usually easy to find a pointer to simple uchar[].
Steps to start native code debugging:
Ok, let’s find a key for levels lua files:
(gdb) br _ZN7GameLua9loadLevelEN4lang6StringE Breakpoint 1 at 0x80468e4c
(gdb) c Continuing. [New Thread 5857] [Switching to Thread 5857] Breakpoint 1, 0x80468e4c in GameLua::loadLevel () from /home/brutall/t-angrybirds/com.rovio.angrybirdsrio-1/obj/local/armeabi/libangrybirds.so
(gdb) x/4x $r1 0x4395e66c: 0x00a405f0 0x00153b28 0x804ec778 0x00000000 (gdb) x/s 0x00a405f0 0xa405f0: "levels/warehouse/Level190"
Yey, finally we see something
(gdb) advance _ZN4lang7AESUtil7decryptERKNS_5ArrayIhEES4_RS2_ 0x80539894 in lang::AESUtil::decrypt () from /home/brutall/t-angrybirds/com.rovio.angrybirdsrio-1/obj/local/armeabi/libangrybirds.so
(gdb) x/4x $r1 0x1592b0: 0x00159528 0x00000020 0x00000020 0x7b206e65
0×00000020 = 32 – yes, length of AES key First 4 bytes of an Array object is a pointer to raw char[] and second 4 bytes contain length of an array. Now we could read contents of an Array:
(gdb) x/s 0x00159528 0x159528: "USCaPQpA4TSNVxMI1v9SK9UC0yZuAnb2a"
As you can see there are 33 chars instead of 32. This is because Array stores its length, so char[] isn’t null-terminated. Ignore last “a” char.
(gdb) x/4x $r2 0x4395d6f4: 0x009ca248 0x000004a0 0x000004a0 0x00000378 (gdb) x/4x 0x009ca248 0x9ca248: 0x3347b5dc 0x26048446 0x1a0c1231 0x35d3f99c
First 16 bytes are the same, length of data is also ok.
As you can see there is AES::BlockMode passed to AES:ecrypt(). It would be quite hard to interpret it without headers, so I was trying various block modes and I found that CBC with empty initial vector decodes to string starting with ’7z’. For me that meant: mission successfull
Ok, highscores.lua and settings.lua files now. Technique is very similar, but there are some differences:
Maybe there is a better solution to last problem, but I’ve decided to add some Thread.sleep() call just after System.loadLibrary(), so gdb will attach before highscores.lua loading.
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V const-wide/16 v0, 5000 invoke-static {v0, v1}, Ljava/lang/Thread;->sleep(J)V
(gdb) br _ZN7GameLua18loadPersistentFileERKN4lang6StringE Breakpoint 1 at 0x80457030 (gdb) c Continuing. [New Thread 6735] [Switching to Thread 6735] Breakpoint 1, 0x80457030 in GameLua::loadPersistentFile () from /home/brutall/t-angrybirds/com.rovio.angrybirdsrio-1/obj/local/armeabi/libangrybirds.so (gdb) x/s $r2 0x4395e3b8: "highscores.lua"
I’m not sure why it’s R2, not R1 and why there is no lang::String, but char[] directly. I think this isn’t a pointer to String, but String itself, passed to method in registers, so its char[] is in R2.
(gdb) advance _ZN4lang7AESUtil7decryptERKNS_5ArrayIhEES4_RS2_ 0x80539894 in lang::AESUtil::decrypt () from /home/brutall/t-angrybirds/com.rovio.angrybirdsrio-1/obj/local/armeabi/libangrybirds.so (gdb) x/4x $r1 0x159294: 0x00159620 0x00000020 0x00000020 0x00159518 (gdb) x/s 0x00159620 0x159620: "44iUY5aTrlaYoet9lapRlaK1Ehlec5i0"
(gdb) x/4x $r2 0x4395ddc4: 0x0015bc00 0x00000040 0x00000040 0x00000001 (gdb) x/16x 0x0015bc00 0x15bc00: 0x2271b777 0xe6f19f4c 0x2489a316 0xfae1aee2 0x15bc10: 0x82e0ef38 0xe84fc25d 0xb196adac 0xbf030439 0x15bc20: 0xb6b9bade 0x3046af12 0xe8eeeb0d 0x20e8037c 0x15bc30: 0x1a405edf 0xc218f7f6 0xc29209e2 0x9ad03e8c
Yeah, this is my highscores.lua file.
Now we have got everything we want
Ahh, not exactly everything… I would be really happy to know, how to properly attach IDA for debugging – it would be much easier, even if gdb interface is also very good.
哦,忘了说一下这篇文章的作者,Brut.all,看到这个名字你应该就能够联想到,如果你有一台Android智能手机的话。没错,这位就是Brut Google Maps的作者,我的手机上就有他的App,另外他还发布了ApkTool,在Google Code上的开源工具,专门用来对apk做反向工程,当然现在也还用不着。
原创文章,转载请注明: 转载自All-iPad.net
本文链接地址: 如何用gdb找到Android so文件中的加密key