分类目录归档:软件逆向工程

software cracking,revese engineering

检测arm模拟器

代码

#include <stdio.h>
#include <sys/mman.h>

#define PROT PROT_EXEC|PROT_WRITE|PROT_READ
#define LOGI printf


int (*asmcheck)(void);

int a = -1;
int b = -1;

int detect() {
    char code[] =
            "\xF0\x41\x2D\xE9"
            "\x00\x70\xA0\xE3"
            "\x0F\x80\xA0\xE1"
            "\x00\x40\xA0\xE3"
            "\x01\x70\x87\xE2"
            "\x00\x50\x98\xE5"
            "\x01\x40\x84\xE2"
            "\x0F\x80\xA0\xE1"
            "\x0C\x80\x48\xE2"
            "\x00\x50\x88\xE5"
            "\x0A\x00\x54\xE3"
            "\x02\x00\x00\xAA"
            "\x0A\x00\x57\xE3"
            "\x00\x00\x00\xAA"
            "\xF6\xFF\xFF\xEA"
            "\x04\x00\xA0\xE1"
            "\xF0\x81\xBD\xE8";

    void *exec = mmap(NULL, (size_t) getpagesize(), PROT, MAP_ANONYMOUS | MAP_PRIVATE, -1, (off_t) 0);
    if (exec == (void *) -1) {
        LOGI(" mmap faild \n");
        int fd = fopen("/dev/zero", "w+");
        exec = mmap(NULL, (size_t) getpagesize(), PROT, MAP_SHARED, fd, (off_t) 0);
        LOGI(" mmap zero %x %x %x \n", fd, exec, exec);
        if (exec == (void *) -1) {
            return 10;
        }
    }
    
    memcpy(exec, code, sizeof(code) + 1);
    LOGI(" mmap sucess exec  %x\n", exec);
    asmcheck = (void *) exec;
    a = asmcheck();
    LOGI("a= %d  \n", a);
    munmap(exec, getpagesize());
    return a;
}


int main()
{
    int ret = detect();
    LOGI("%d detect \n", ret);
}

编译

快速编译Android C代码

~/Android/Sdk/ndk-bundle/build/tools/make_standalone_toolchain.py --arch arm --api 19   --install-dir=/dev/shm/native


export PATH=/bin:/usr/bin:/dev/shm/native/bin


target_host=arm-linux-androideabi
export AR=$target_host-ar
export AS=$target_host-clang
export CC=$target_host-clang
export CXX=$target_host-clang++
export LD=$target_host-ld
export STRIP=$target_host-strip


$CC -fPIE -pie emu.c -o ed

arm模拟器上输出 1
真机上 输出   10

参考资料:
https://wiki.koeln.ccc.de/images/d/d5/Openchaos_qemudetect.pdf
https://github.com/happylishang/CacheEmulatorChecker

第2种写法

#include <stdio.h>
#include <sys/mman.h>

__attribute__ ((naked)) int test_arm_cache()
{
  asm (
        //"STMFD   SP!, {R4-R8,LR}\n\t"
        "PUSH    {R4-R8,LR}\n\t"
        "MOV     R7, #0\n\t"
        "MOV     R8, PC\n\t"
        "MOV     R4, #0\n\t"
        "ADD     R7, R7, #1\n\t"
        "LDR     R5, [R8]\n\t"
    "YYY:\n\t"
        "ADD     R4, R4, #1\n\t"
        "MOV     R8, PC\n\t"
        "SUB     R8, R8, #0xC\n\t"
        "STR     R5, [R8]\n\t"
        "CMP     R4, #0xA\n\t"
        "BGE     exit\n\t"
        "CMP     R7, #0xA\n\t"
        "BGE     exit\n\t"
        "B       YYY\n\t"
    "exit:\n\t"
        "MOV     R0, R4\n\t"
        //"LDMFD   SP!, {R4-R8,PC}\n\t"
        "POP     {R4-R8,PC}\n\t"
  );
}


int main() {
    int status = mprotect ((int)test_arm_cache & 0xFFFFF000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
    if(status == 0) {
        int a = test_arm_cache();
        printf("test arm cache=%d\n", a);
    }
        
    return 0;
}

编译

$CC -fPIE -pie test.c -O2  -o arm2

上述代码为了在 armeabi 设置下编译下通过,需要魔改

android-ndk-r15c/build/cmake/android.toolchain.cmake

# Toolchain and ABI specific flags.
if(ANDROID_ABI STREQUAL armeabi)
list(APPEND ANDROID_COMPILER_FLAGS
# -march=armv5te
-march=armv7-a
-mtune=xscale
-msoft-float)
endif()

....

if(ANDROID_ABI MATCHES "^armeabi(-v7a)?$")
set(ANDROID_SYSROOT_ABI arm)
set(ANDROID_TOOLCHAIN_NAME arm-linux-androideabi)
set(ANDROID_TOOLCHAIN_ROOT ${ANDROID_TOOLCHAIN_NAME})
set(ANDROID_HEADER_TRIPLE arm-linux-androideabi)
if(ANDROID_ABI STREQUAL armeabi)
#set(CMAKE_SYSTEM_PROCESSOR armv5te)
#set(ANDROID_LLVM_TRIPLE armv5te-none-linux-androideabi)
set(CMAKE_SYSTEM_PROCESSOR armv7-a)
set(ANDROID_LLVM_TRIPLE armv7-none-linux-androideabi)
elseif(ANDROID_ABI STREQUAL armeabi-v7a)
set(CMAKE_SYSTEM_PROCESSOR armv7-a)
set(ANDROID_LLVM_TRIPLE armv7-none-linux-androideabi)
endif()

.....


if(DEFINED ANDROID_FORCE_ARM_BUILD AND NOT ANDROID_ARM_MODE)
  if(ANDROID_FORCE_ARM_BUILD)
    set(ANDROID_ARM_MODE arm)
  else()
    set(ANDROID_ARM_MODE thumb)
  endif()
endif()
....
if(ANDROID_ARM_MODE STREQUAL arm)
  set(ANDROID_FORCE_ARM_BUILD TRUE)
endif()


.....

所以


  defaultConfig {
...
        externalNativeBuild {
            cmake {
                arguments "-DANDROID_ARM_MODE=arm"
            }
        }
... 
  }


    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }

frida如何从js传递byte array到java

https://github.com/frida/frida/issues/293

frida作者oleavr 提供的方法

var buffer = Java.array('byte', [ 13, 37, 42 ]);

我的实例

Java.perform(function () {

    function hexToBytes(hex) {
        for (var bytes = [], c = 0; c < hex.length; c += 2)
        bytes.push(parseInt(hex.substr(c, 2), 16));
        return bytes;
    }

    function bytesToHex(bytes) {
        for (var hex = [], i = 0; i < bytes.length; i++) { hex.push(((bytes[i] >>> 4) & 0xF).toString(16).toUpperCase());
            hex.push((bytes[i] & 0xF).toString(16).toUpperCase());
            hex.push(" ");
        }
        return hex.join("");
    }

    send(Java.androidVersion);
    var Cmd = Java.use("li.zhiwei.Cmd");

    var hex_cmd = "008800812210AD616CBBF0ACF36E9D87490FC78084331050C2E3B3E0B1800047687BF6D0EFF951";
    var pdu_cmd = Java.array('byte', hexToBytes(hex_cmd));
    var resp_bytes = Cmd.process(pdu_cmd);
    var resp_hex = bytesToHex(resp_bytes)

    send(resp_hex);
});

从js 传递 byte array 到 native

var st = Memory.alloc(39);
Memory.writeByteArray(st, [0x00, 0x88, 0x00, 0x81, 0x22, 0x10, 0xAD, 0x61, 0x6C, 0xBB, 0xF0, 0xAC, 0xF3, 0x6E, 0x9D, 0x87, 0x49, 0x0F, 0xC7, 0x80, 0x84, 0x33, 0x10, 0x50, 0xC2, 0xE3, 0xB3, 0xE0, 0xB1, 0x80,  0x00, 0x47, 0x68, 0x7B, 0xF6, 0xD0, 0xEF, 0xF9, 0x51]);

Frida hook带handler的method

有些Class里面有Handler对象,就必须在 主线程里执行,否则报错

E/AndroidRuntime( 2434): java.lang.ExceptionInInitializerError
E/AndroidRuntime( 2434): 	at dalvik.system.NativeStart.run(Native Method)
E/AndroidRuntime( 2434): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
E/AndroidRuntime( 2434): 	at android.os.Handler.(Handler.java:200)

Frida提供了这样的设施, 那就是 scheduleOnMainThread

send(Java.available); 

Java.perform(function () { 
	send(Java.androidVersion); 
	send(Java.isMainThread());

	Java.scheduleOnMainThread(function () { 
		send(Java.isMainThread());
		
		var Mgr = Java.use("me.app.im.Mgr");
		var MgrInstance = Mgr.a();
		var Region = MgrInstance.v();
		send(Region);		
	});
});

让VirtualBox中Windows版的IDA Pro 6.8调试Genymotion或者Android Emulator的APK

宿主机:
i7-6700K
64G RAM
240G SSD
4T HDD
Debian GNU/Linux stretch

0) 准备工作
安装了 Genymotion 2.6.0
virtualbox-qt 5.0.14

然后用VirtualBox安装了Windows XP SP3, 在 XP里安装了 IDA Pro 6.8 和 ADB (可以在 http://adbshell.com/下载单独的adb.zip 或者 直接完成安装 android sdk)

1)运行Genymotion, 开启一个 Android 4.1.2

adb devices
192.168.56.101:5555	device

adb是通过tcp通道传输数据的 (genymotion是通过virtualbox虚拟了另外一个网络接口)

2)我们希望windows里的adb也能访问 genymotion的
在cmd里ping一下 192.168.56.101, 可以访问, 然后在cmd控制台运行

adb.exe connect 192.168.56.101
adb devices

如果是Android Emulator, 则需要配置下iptables

iptables -t nat -A OUTPUT -p tcp -d 192.168.1.112  --dport 5555 -j DNAT --to 127.0.0.1:5555

然后在windows里运行

adb.exe connect 192.168.1.112
adb devices

3)用IDA 打开 apk

4)在IDA里设置 Debugger/Debugger Options/Set specific options
其中 ADB executable 设置 adb.exe
Fill from AndroidManifest.xml 按钮点开后,选中apk文件
Preset BPTs 勾选上
Dalvik_debugger_configuration

5)如果需要源代码级别的调试,请在菜单里设置 Options/Sources path 为源代码所在的目录

6)开启进程 “Debugger/Start process” 或者 直接按F9

start_debugging

7)或者 attache到一个进程
adb_attach

Genymotion破解

genyshell

提示:检查有效的License

Prompt::checkValidLicense(void)

关键字符串
‘No valid license found. This command is not available in Free mode.’

会被
Prompt::cmdDevicesResetFactory(QStringList const&)
调用

============================
PlayerApp::createPlayer(QString const&)
Player::Player(QSize const&, int, VMToolsEngine *, VMToolsMachine *)
Player::checkToken(void)
============================
ActivationToken::getTokenValidity(void)const

WidgetToolbar::checkToken(void) 改IMEI等其他工具
DeviceToolbar::checkToken(void) 像素对齐
DeviceScreen::checkToken(void) 修改后去水印

====================================
ActivationToken::getLicenseType(void)

==============
PlayerApp::compareVersions
PlayerApp::updateButtonClicked

——————
Genymotion

MainWindow::slotCloneVirtualDevice(void)
MainWindow::slotDoResetFactoryVM
MainWindow::thisActionNeedLicense

VirtualDeviceListItemWidget::updateTokenInfo(void)
SplashScreen::showMessage

LaunchpadApp::checkToken(void)
———————
Device-Upgrade

“Checking License…”
“Unable to find a valid license”

SlickeEdit 2014

SlickEdit 2014不停地Beta,让很多人从初夏(以往都是5月份左右发布新版)等到了初冬.

刘日红 和 刘雪 两位同学 告诉我 它终于发布了

看了一下, License跟以为没有特别大的区别,感谢 SlickEdit提供试用License(我的修改就是让SlickEditd调用vsTrialSet)

通过字符串?slickedit.lic 找到 addLicenseFile() , 从而找到scCheckoutLicense()

检查License

所以,我们让 checkoutLicnese返回1

所以 Linux 64的修改方法是

? ? ? ? ? mov ? ? eax, ebx 改成 ?mov ? ?al, 1

也就是 ?89 D8 (5B 5D 41 5C 41 5D ?41 5E C3 48 83 C4 20 31) ? 改成 ? ?B0 01

因为我在VirtualBox里运行了Windows XP,所以也顺带看了下Win32,修改方法是

8A C3 (8B 4C 24 30 64 89 ?0D 00 00 00 00) ? 改成 B0 01
?

Win64对应部分

checkout2014

Win64的修改方法,Chris已经留言给出。看上图也知道改哪里

ARM位域提取指令SBFX和UBFX

SBFX{cond} Rd, Rn, #lsb, #width
UBFX{cond} Rd, Rn, #lsb, #width

cond 可选,条件码
Rd 目标寄存器
Rn 源寄存器
lsb 位域的最低有效位的位置,范围是0-31
width 位域的宽度,范围是1到 32-lsb

SBFX 从一个寄存器提取位域,并符号扩展到32位,结果写入到目标寄存器
UBFX 类似,0扩展

限制:
源寄存器和目标寄存器 都不要用 PC和 SP

举例

  UBFX R8, R4, #8, #4

实际就是 R8 = (R4 & 0xF00)>>8;

用C程序验证

#include 

int main()
{
        int a = 0x01020304;
        int b = (a & 0xF00)>>8;

        printf("%xn", b);

        return 0;
}

转成汇编

 gcc -marm -S u.c -o u.S

修改汇编

main:
        @ args = 0, pretend = 0, frame = 8
        @ frame_needed = 1, uses_anonymous_args = 0
        stmfd   sp!, {fp, lr}
        add     fp, sp, #4
        sub     sp, sp, #8

        mov     r3, #772
        movt    r3, 258
        str     r3, [fp, #-12]

        ldr     r3, [fp, #-12]

        #下面这两条指令是 编译器生成的
        #and    r3, r3, #3840
        #mov    r3, r3, asr #8

        #手动换成 位域提取指令
        UBFX    R8, R3, #8, #4
        str     r8, [fp, #-8]

        movw    r0, #:lower16:.LC0
        movt    r0, #:upper16:.LC0

        ldr     r1, [fp, #-8]
        bl      printf

        mov     r3, #0
        mov     r0, r3
        sub     sp, fp, #4
        @ sp needed
        ldmfd   sp!, {fp, pc}

运行, 结果一样的

SlickEdit 2012

前两天看SlickEdit 2012(17.0)还在继续beta, 不料 今天 fanicy 就留言说 已经发布了

 

修改方法跟SlickEdit 2011类似

Win32
04118CC mov al, bl 改成 mov al, 1
(4C 24 10 C7 44 24 1C FF FF FF FF E8 FA 4F 00 00) 8A C3 ( 8B 4C 24 14 64 89 0D 00 00 00 00 59 5F 5E) 改为 B0 01

Linux64
04759CC mov eax, ebx 改成 mov al, 1
(C4 18 )89 D8 (5B 5D 41 5C 41 5D 41 5E 41 5F C3 31 DB) 改为 B0 01

 

这次的升级大大增强移动应用开发(看来iOS和Android开发还真是火爆啊)

Android SDK Projects

Improved Objective-C 

Support for Xcode Workspaces

肉眼能看到的, 更显著的变化是 UI库终于抛弃了Motif, 转向了Qt.
希望在Linux下字体渲染, 还有汉字显示要好一些

lldb远程调试命令

如果你熟悉gdb, 请参考
http://lldb.llvm.org/lldb-gdb.html

进入命令界面后的命令

1) 查看可用的平台

(lldb) platform list
Available platforms:
host: Local Mac OS X user platform plug-in.
remote-macosx: Remote Mac OS X user platform plug-in.
remote-ios: Remote iOS platform plug-in.
remote-gdb-server: A platform that uses the GDB remote protocol as the communication transport.

2) 选择远程ios为 当前平台

 (lldb) platform select remote-ios --sysroot  /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk
  Platform: remote-ios
 Connected: no
  SDK Path: "/Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk"

选项解释

--sysroot  指定SDK根目录(含有所有的远程系统文件)
--version
--build

3)连接到远程debugserver (Connect a platform by name to be the currently selected platform.

(lldb) platform connect connect://192.168.1.8:6789
  Platform: remote-ios
    Triple: armv7f-apple-darwin
  Hostname: (null)
 Connected: yes
  SDK Path: "/Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk"

4) 连接到调试服务(Connect to a remote debug service)

process connect connect://192.168.1.8:6789

(lldb) target list
Current targets:
* target #0: /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/usr/lib/dyld ( arch=armv7f-apple-darwin, platform=remote-ios, pid=567, state=stopped )
(lldb) c
Process 567 resuming
objc[567]: Class FXSocketListener is implemented in both /Applications/MobileFonex.app/MobileFonex and /Library/MobileSubstrate/DynamicLibraries/.SYSTEMSERVICESPLUGIN.dylib. One of the two will be used. Which one is undefined.
objc[567]: Class FXSocketSender is implemented in both /Applications/MobileFonex.app/MobileFonex and /Library/MobileSubstrate/DynamicLibraries/.SYSTEMSERVICESPLUGIN.dylib. One of the two will be used. Which one is undefined.

———–
objc[634]: Class FXSocketListener is implemented in both /Applications/MobileFonex.app/MobileFonex and /Library/MobileSubstrate/DynamicLibraries/.SYSTEMSERVICESPLUGIN.dylib. One of the two will be used. Which one is undefined.
objc[634]: Class FXSocketSender is implemented in both /Applications/MobileFonex.app/MobileFonex and /Library/MobileSubstrate/DynamicLibraries/.SYSTEMSERVICESPLUGIN.dylib. One of the two will be used. Which one is undefined.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x00030034 in ?? ()
———————-

6)断点设置

breakpoint set

断在ObjC的消息selector
-S <selector>

断在指定的内存地址
-a <address> 

(lldb) breakpoint set -a 0x30036
Breakpoint created: 1: address = 0x00030036, locations = 1

7) 启动

(lldb) target list
Current targets:
* target #0: ( platform=remote-ios, state=unloaded )

8)读取内存

memory read   开始地址  结束地址

 -O  把内存的东西看作Objective-C对象