So Tired !_! 逆水行舟, 不进则退!

22Mar/16

如何利用NFC伪造一张门禁卡

Posted by Nick Xu

0×00 前言

我租住的杭州一个老小区一年前出现了所谓的“出租房杀人事件”,事件过后民警叔叔们给小区的每个单元都装上了门禁,所有住户都需要在物业处登记,物业的工作人员会让你提供身份证或者公交卡用来注册,注册之后就可以刷卡进门了。

但由于某些原因,我并不想去登记注册一张门禁卡,正好手头有一部nexus5,众所周知nexus5是有nfc功能的,我便想能不能用nexus5的nfc功能伪造一张门禁卡呢? 一番尝试之后,就有了下文的方法。 (从来没接触过无线安全,对Proxmark3,acr122u 等设备也是一窍不通,各位大牛见笑了)

0×01分析

由于身份证,公交卡等很多卡都可以用来当门禁卡,那基本上有九成把握这个门禁只是简单读取卡的id,并不会去解密里面的内容,只要简单模拟一个相同id的卡就可以刷开门禁。

0×02“采样”

我们下载一款名为“TagInfo”的android应用,用它来读取一下现在可以刷开门禁的卡信息。(跟同楼的妹子借的)

如下图:

卡的id为:D2:69:76:5B

接着我们找另一台nexus5看一下手机原来的id,扫描出来这台nexus5的id是在不停变化的,如下图:

原来出于安全考虑,android手机的id是一个4个字节长度的随机id,每次连接都会变化,并且都以 “0×80”开头。

android官方并没有提供任何的api可以指定修改nfc的id,但是我们可以用直接修改配置文件的方式来实现,前提当然是手机必须root过了。

0×03Just Do IT

1、到手机的 /etc/ 目录找一个文件名为libnfc-brcm-20791b05.conf,默认情况下,文件中NFA_DM_START_UP_CFG 的配置项是这样的值:

1
{45:CB:01:01:A5:01:01:CA:17:00:00:00:00:06:00:00:00:00:0F:00:00:00:00:E0:67:35:00:14:01:00:00:10:B5:03:01:02:FF:80:01:01:C9:03:03:0F:AB:5B:01:00:B2:04:E8:03:00:00:CF:02:02:08:B1:06:00:20:00:00:00:12:C2:02:00:C8}

2、通过修改这个值就可以改变id。把该文件下载到电脑上,先在最后面增加一个0×33作为标志位,接着接上要指定的id长度,在当前的情况下就是0×04,最后在后面接上要制定的id:“0xD2,0×69,0×76,0x5B”,接着改变最首的数字,加上我们总共增加的字符串长度,这里我们需要加上6,所以最后配置项变成:

1
{4B:CB:01:01:A5:01:01:CA:17:00:00:00:00:06:00:00:00:00:0F:00:00:00:00:E0:67:35:00:14:01:00:00:10:B5:03:01:02:FF:80:01:01:C9:03:03:0F:AB:5B:01:00:B2:04:E8:03:00:00:CF:02:02:08:B1:06:00:20:00:00:00:12:C2:02:00:C8:33:04:D2:69:76:5B}

3、采用adb的方式覆盖系统中原来的文件,然后重启

adb root
adb remount
adb push libnfc-brcm-20791b05.conf /etc/
adb reboot

重启之后我们发现,这台nexus5的id已经被改成了我们想要的。

 

 

拿着修改好的nexus5去试试看?记得必须在唤醒屏幕的情况下nfc才有效。

Tagged as: , Comments Off
22Mar/16

Mac OS X 下部分Android手机无法连接adb问题之解决方案

Posted by Nick Xu

打开终端,在任意当前路经下都可以直接执行adb命令,通过USB线将Android手机和Mac PC连接后,adb devices,没有相应设备的列表。下面是解决办法:
1. 打开终端,输入:system_profiler SPUSBDataType,查看Mac系统所有USB设备信息,找到相应的厂商Vender ID。
查到相应连有Android手机设备的usb hub,找到相应的厂商Vender ID,比如,我的测试机K-Touch T619天语手机就无法连接adb,查到的相应信息片段如下:
  1. -----------------
  2.  Spreadtrum phone:
  3.               Product ID: 0x5d04
  4.               Vendor ID: 0x1782
  5.               ...
  6.        Serial Number: T619
  7.        ...
  8. -----------------

2. 终端进入/Users/user/.android,应该有一个adb_usb.ini文件,如果没有就创建,然后将上面的Vender ID “0x1782”单独一行加入到该文件,然后退出。

  1. # ANDROID 3RD PARTY USB VENDOR ID LIST -- DO NOT EDIT.
  2. # USE 'android update adb' TO GENERATE.
  3. 1 USB VENDOR ID PER LINE.
  4. 0x1782

3. 重启adb server进程。

终端依次执行下面命令:
  1. adb kill-server
  2. adb start-server

然后通过adb devices命令就可以查看到以相应设备Serial Number为名字的设备。如:

  1. -MacBook-Pro:.android user$ adb devices
  2. List of devices attached
  3. emulator-5554   device
  4. T619    device

PS:

1. 有时 adb devices不能显示连接设备,需要拔掉数据线,多插几次,并且退出终端,然后重新打开,再输入命令就能发现连接的设备,再无法连接请重启电脑,等待系统初始化环境设置。
需要注意的是并不是所有的android机器都能解决,比如有的手机有供应商ID,缺少产品ID,依然无法识别,这种奇葩形的就只能找其它方法了。
2. Windows(XP、7)下面也可以同样的方法解决。但是前提也是已经指定了adb环境变量并且安装了相应Android手机设备的adb usb驱动,判断有没有装通过将手机和Windows连接,设备管理器里面没有发现显示有问号的设备就说明装了,有就说明没有安装。然后在C:\Users\username\.android目录下面也有一个adb_usb.ini文件,像前面那样别起一行添加相应设备的Vender ID,重启adb server进程即可。
3. 如果发现无法启动ADB SERVER, 运行下面这行查看具体原因:
adb nodaemon server
Tagged as: , , Comments Off
26Feb/16

Missing IOS Distribution Signing Identity For

Posted by Nick Xu

The issue is because the Apple WWDRCA expired today (Feb 14, 2016):https://developer.apple.com/support/certificates/expiration/

Open Keychain Access, and in the menu, click View -> Show Expired Certificates. Then, delete the expired Apple Worldwide Developer Relations Certificate Authority from both the login andSystem Keychains. Install the renewed certificate from Apple by downloading from https://developer.apple.com/certificationauthority/AppleWWDRCA.cer and then opening it.

Also you will need to do restart xcode to reflects the changes -> Clean your project -> Build then try again to generate your archive. Ref: Your keychain should show like that

22May/15

Openssl移植到Android

Posted by Nick Xu

Openssl移植到Android都是使用别人提好(从Android源码)的Openssl代码,方法简单但过程不那么顺利,因为Openssl版本变动太频繁了,再加上NDK一堆BUG,极不愿意去调试原始配置,单单Openssl的模块编译前后就等了两个月直到Google推出NDK新版本R8C才编译通过。因为原生程序应用到很多Openssl签名、验证算法函数,就连Openssl的版本升级一下往往都要修改一些代码才能通过。

一、下载Openssl最新版本

可选的Openssl Android版本下载地址:

Openssl 1.0.0a:

https://github.com/guardianproject/openssl-android

Openssl 1.0.1c:

https://github.com/aluvalasuman/OpenSSL1.0.1cForAndroid

本文将要使用的Openssl版本为1.0.1c,前一1.0.0a版本未验证通过(NDKr8b),编译时会出现下文的编译错误。所以改用较新版本,目前已知1.0.1c在NDK r8b上编译会有很多问题,不是Openssl工程有兼容BUG就是NDK版本有BUG,反正不是那么容易调试通过。

二、编译过程

本文编译使用最新的NDK r8c(Ubuntu 12.04),下载Openssl android工程后解压,可以看到完整的NDK工程,简单的编译过程如下:

  1. 进入解压目录,执行:
  2. $NDK_HOME/ndk-build clean
  3. $NDK_HOME/ndk-build
  4. 编译结果在obj目录下(libcrypto-static.a和libssl-static.a或是libcrypto.so和libssl.so)
  5. 把结果拷贝出来放到自己的Android工程Helloworld对应目录下进行调用即可。

上述步骤4编译出Openssl的链接库,一般拷贝到ndk_r8c\platforms\android-10\arch-arm\usr\lib目录下(仅为示例),然后把openssl根下的include目录都拷贝出去就是编译头文件,这样就可以构建自己的helloworld工程了,在helloworld的Android.mk中增加类似如下调用:

LOCAL_LDLIBS := -L$(SYSROOT)/lib/ -llog -lcrypto -lssl

三、常见错误

以下编译错误,有的在1.0.0a版本中遇到,有的是在NDK r8b环境下遇到,此间涉及到OpenSSL版本问题、GCC版本问题、NDK版本BUG问题,等等都混到一起总结方便对应处理。

1、undefined reference to `zError'

openssl 库时错误如下:

SharedLibrary  : libssl.so
Executable     : openssl
/root/android-ndk-r8b/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6.x-google/../../../../arm-linux-androideabi/bin/ld: warning: libz.so, needed by ./obj/local/armeabi/libcrypto.so, not found (try using -rpath or -rpath-link)

./obj/local/armeabi/libcrypto.so: undefined reference to `zError'
./obj/local/armeabi/libcrypto.so: undefined reference to `inflateEnd'
./obj/local/armeabi/libcrypto.so: undefined reference to `deflate'
./obj/local/armeabi/libcrypto.so: undefined reference to `deflateInit_'
./obj/local/armeabi/libcrypto.so: undefined reference to `inflate'
./obj/local/armeabi/libcrypto.so: undefined reference to `deflateEnd'
./obj/local/armeabi/libcrypto.so: undefined reference to `inflateInit_'
collect2: ld returned 1 exit status

解决办法:

1、$NDK_HOME/ndk-build NDK_TOOLCHAIN_VERSION=4.4.3

$NDK_HOME/ndk-build NDK_TOOLCHAIN=arm-linux-androideabi-4.4.3

该方法参考来自:android-ndk-r8b/doc/NDK-BUILD.html 说明,ndk-build可以携带 NDK_XXX这样的参数,来指定编译环境版本信息。具体参数有哪些?目前可以通过android-ndk-r8b/build/core/init.mk里查询到一些NDK_开头的参数。

2、在openssl的jni目录下的Application.mk中增加:

APP_PLATFORM := android-8

3、在openssl根下的android-config.mk中增加:

APP_ABI := armeabi armeabi-v7a

该参考来源android-ndk-r8b/docs/APPLICATION-MK.html

2、Unknown EABI object attribute 44

SharedLibrary  : libssl.so
/root/android-ndk-r8b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld: Warning: /root/android-ndk-r8b/platforms/android-8/arch-arm/usr/lib/crtend_so.o: Unknown EABI object attribute 44
Executable     : openssl
/root/android-ndk-r8b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld: Warning: /root/android-ndk-r8b/platforms/android-8/arch-arm/usr/lib/crtend_android.o: Unknown EABI object attribute 44
Install        : openssl => /root/aluvalassuman/libs/armeabi/openssl
Install        : libssl.so => /root/aluvalassuman/libs/armeabi/libssl.so
Compile thumb  : ssltest <= ssltest.c
Executable     : ssltest
/root/android-ndk-r8b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld: Warning: /root/android-ndk-r8b/platforms/android-8/arch-arm/usr/lib/crtend_android.o: Unknown EABI object attribute 44
Install        : ssltest => /root/aluvalassuman/libs/armeabi/ssltest

解决办法:

4.4.3似乎跟链接库的编译环境可能对不上(44冲突),网上有说改成4.6就没问题了,不会出现该提示,但是4.6支持STL有BUG啊?

crypto/Android.mk 大约535行,添加:

LOCAL_EXPORT_LDLIBS := -lz

注意有没添加以下两个静态库,大约576行,添加(暂时不用):

LOCAL_LDLIBS := -lz –ldl

3、build/gmsl/__gmsl:512: *** non-numeric second

Complile Openssl:

Error:
build/gmsl/__gmsl:512: *** non-numeric second
Changes:

I changed the file  __gmsl, the second wordlist argument(line 512),
and it's running my jni example without errors:

int_encode = $(__gmsl_tr1)$(wordlist 1, $1,$(__gmsl_input_int))

to:

int_encode = $(__gmsl_tr1)$(wordlist 1,$(words $1),$
(__gmsl_input_int))

参考资料(下述可能有地址被墙了):

http://www.uml.org.cn/mobiledev/201108101.asp

http://blog.csdn.net/someonea/article/details/6312213

http://ssuman185.blogspot.sg/p/steps-for-porting-openssl-for-android.html

http://stackoverflow.com/questions/11856688/openssl-build-issue-with-android-ndk-r8

http://stackoverflow.com/questions/11929773/compiling-the-latest-openssl-for-android

https://groups.google.com/forum/?fromgroups=#!topic/android-ndk/b4DSxE1NAS0

10Jul/14

Smali注入之打造属于自己的安卓crack利器

Posted by Nick Xu

关于Smali注入大家应该了解过,网上有不少教程。那些注入代码看上去简单,实际用起来得花不少功夫。

普通的注入就是在软件源代码中添加几行代码,用于改变软件的功能,或查看某个寄存器在运行中具体的值。

需要注意的地方是:添加的注入代码所使用的寄存器不影响其他代码的执行。当注入代码较多时,这个要求就变得很困难了。

在这里我的解决办法是:把注入代码写进自己专属的crack.smali,然后在要注入的地方调用crack.smali里的注入方法即可,只用一行注入代码,而且不影响其他寄存器。

举个例子说明下两种方法的区别,假设原软件中有以下代码:

.method public methodName()Ljava/lang/String;
.locals 4
.prologue
const-string v0, "test1"

const-string v3, "test2"

invoke-static {v0}, Lpackage/name/ObjectName;——>methodName1(Ljava/lang/String;)Ljava/lang/String;

move-result-object v1

invoke-static {v1}, Lpackage/name/ObjectName;——>methodName2(Ljava/lang/String;)Ljava/lang/String;

move-result-object v2

invoke-static {v3}, Lpackage/name/ObjectName;——>methodName3(Ljava/lang/String;)V

new-instance v3, Ljava/lang/StringBuilder;

invoke-direct {v0, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v0

invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v0

return-object v0
.end method

假如我要查看move-result-object v1和move-result-object v2,两处中v1、v2的值该如何注入?

普通的log.d注入方法如下(可以用Logcat查看日志):

.method public methodName()Ljava/lang/String;
.locals 5
.prologue
const-string v0, "test1"

const-string v3, "test2"

invoke-static {v0}, Lpackage/name/ObjectName;——>methodName1(Ljava/lang/String;)Ljava/lang/String;

move-result-object v1

const-string v4, "info"

invoke-static {v4, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

invoke-static {v1}, Lpackage/name/ObjectName;——>methodName2(Ljava/lang/String;)Ljava/lang/String;

move-result-object v2

const-string v4, "info"

invoke-static {v4, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

invoke-static {v3}, Lpackage/name/ObjectName;——>methodName3(Ljava/lang/String;)V

new-instance v3, Ljava/lang/StringBuilder;

invoke-direct {v0, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v0

invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v0

return-object v0
.end method

在上面的代码中,我先是修改了开头的“.locals 5”,表示使用的寄存器为v0-v4。然后我用v4作为log.d的第一个参数,寄存器v1、v2为第二个参数。

由于原代码中,v0、v1、v2、v3从头到尾都有使用,所以注入时使用这几个寄存器会影响软件的正常执行,所以我才修改“.locals”开辟新的寄存器v4。

明显这样注入很麻烦。而且刚好v1、v2都是字符串,符合log.d的要求。如果v1、v2为整数值,注入就更加复杂了。

下面看看创建了crack.smali的注入会如何。

假设我已经有了个crack.smali,代码如下:

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
.class public Lcrack;
.super Ljava/lang/Object;
.source "crack.java"
.method public static log(Ljava/lang/String;)V
    .locals 1
    .prologue
    const-string v0, "info"
    invoke-static {v0, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    return-void
.end method

把crack.smali放到反编译后的smali根目录,在源代码中注入:

.method public methodName()Ljava/lang/String;
.locals 4
.prologue
const-string v0, "test1"

const-string v3, "test2"

invoke-static {v0}, Lpackage/name/ObjectName;——>methodName1(Ljava/lang/String;)Ljava/lang/String;

move-result-object v1

invoke-static {v1}, Lcrack;->log(Ljava/lang/String;)V

invoke-static {v1}, Lpackage/name/ObjectName;——>methodName2(Ljava/lang/String;)Ljava/lang/String;

move-result-object v2

invoke-static {v2}, Lcrack;->log(Ljava/lang/String;)V

invoke-static {v3}, Lpackage/name/ObjectName;——>methodName3(Ljava/lang/String;)V

new-instance v3, Ljava/lang/StringBuilder;

invoke-direct {v0, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v0

invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v0

return-object v0
.end method

明显比前面的注入方式简单多了。crack.smali的方法可以不断丰富,需要用时信手拈来。

既然如此,就让我们打造属于自己的安卓crack利器吧!

最基本的crack.smali推荐加入log日志输出,代码如下:

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
.class public Lcrack;
.super Ljava/lang/Object;
.source "crack.java"
.method public static log(Ljava/lang/String;)V
    .locals 1
    .prologue
    const-string v0, "info"
    invoke-static {v0, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    return-void
.end method

把crack.smali放进smali目录,在要查看的,保存了字符串的寄存器vx的下面,添加代码:

[Java] 纯文本查看 复制代码
1
invoke-static {vx}, Lcrack;->log(Ljava/lang/String;)V

保存并重新编译,在手机或模拟器上安装软件,连上电脑,打开cmd命令行:

<ignore_js_op>

cd到桌面,然后输入命令adb logcat>test.txt,然后在手机上运行软件,当软件执行了注入的代码(自行判断),按ctrl+c结束,然后回到桌面。

如无法识别adb命令,请先添加adb.exe所在位置的环境变量,如我安装了靠谱助手,我找到了它提供的adb.exe所在的路径,然后我照下面图设置:

<ignore_js_op>

打开test.txt,查找d/info,在找到的那一行的右边就是要查看的寄存器的值。

<ignore_js_op>

“info”是由“ const-string v0, "info" ”给出。可以自行修改。

上面的说的命令还可以添加过滤代码,有经验的人自行修改,使得test.txt的内容更简洁。

从上面test.txt的结果可以看出,如果需要注入的位置有多处,那么就很难分辨具体哪个结果对应哪个了。

解决办法是,给crack.smali的log方法加序号,并复制多份log方法,参照下面修改方式,如:

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
.class public Lcrack;
.super Ljava/lang/Object;
.source "crack.java"
.method public static log1(Ljava/lang/String;)V
    .locals 1
    .prologue
    const-string v0, "info1"
    invoke-static {v0, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    return-void
.end method
.method public static log2(Ljava/lang/String;)V
    .locals 1
    .prologue
    const-string v0, "info2"
    invoke-static {v0, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    return-void
.end method

第一处注入调用log1,第二处注入调用log2,依次类推,然后根据序号对应结果。

上面说的注入,前提都是vx是String,如果vx是int型怎么办?

可以给crack.smali添加下面方法:

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
.method public static I(I)V
    .locals 2
    .prologue
    const-string v0, "info_int"
    invoke-static {p0}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
    move-result-object v1
    invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    return-void
.end method

上面方法调用代码为:

[Java] 纯文本查看 复制代码
1
invoke-static {vx}, Lcrack;->I(I)V

vx为要查看的寄存器。

当vx保存的是long型的话,就比较麻烦了,稍微用错就会导致程序停止运行,所以尽量避免查看long型vx。

给crack.smali添加以下代码:

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
.method public static J(J)V
.locals 2
.prologue
const-string v0, "info_long"
invoke-static {p0, p1}, Ljava/lang/String;->valueOf(J)Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
return-void
.end method

上面方法调用代码为:

[Java] 纯文本查看 复制代码
1
invoke-static {vx, vx+1}, Lcrack;->J(J)V

vx为要查看的寄存器,同时确保vx+1在上面的代码中没有被使用过,且在.locals声明的可使用的寄存器范围内。

至于[C、[B、[Ljava/lang/String的查看,有机会再补上。

软件大部分时间都在跟字符串、数据打交道。很多时候就因为某个寄存器的值不知,导致软件代码很难分析下去。

因此在没有调试器的前提下,通过注入查看寄存器的值就变得非常重要了。

总是通过logcat查看寄存器值,多少有点不方便,所以下面讲下如何将字符串输出到文本。

直接用smali写有点麻烦,所以先用java写,编译后再反编译为smali,参考java代码如下:

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.io.*;
import android.util.Log;
public class crack
{
/*将字符串s输出到/sdcard/debug.txt*/
public static void puts(String s)
{
  try
  {
          String path= "/sdcard/debug.txt";
           
                  FileOutputStream outStream = new FileOutputStream(path,false);
                  OutputStreamWriter writer = new OutputStreamWriter(outStream,"gb2312");
                  writer.write(s);
                  writer.flush();
                  writer.close();
                  outStream.close();
  }
                  catch (Exception e)
                  {
                          Log.e("debug", "file write error");
                  }
}
}

反编译后smali代码如下:

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
.method public static puts(Ljava/lang/String;)V
    .locals 7
    .prologue
    :try_start_0
    const-string v3, "/sdcard/debug.txt"
    new-instance v2, Ljava/io/FileOutputStream;
    const/4 v5, 0x0
    invoke-direct {v2, v3, v5}, Ljava/io/FileOutputStream;-><init>(Ljava/lang/String;Z)V
    .line 19
    new-instance v4, Ljava/io/OutputStreamWriter;
    const-string v5, "gb2312"
    invoke-direct {v4, v2, v5}, Ljava/io/OutputStreamWriter;-><init>(Ljava/io/OutputStream;Ljava/lang/String;)V
    .line 21
    invoke-virtual {v4, p0}, Ljava/io/OutputStreamWriter;->write(Ljava/lang/String;)V
    .line 23
    invoke-virtual {v4}, Ljava/io/OutputStreamWriter;->flush()V
    .line 25
    invoke-virtual {v4}, Ljava/io/OutputStreamWriter;->close()V
    .line 27
    invoke-virtual {v2}, Ljava/io/FileOutputStream;->close()V
    :try_end_0
    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
    .line 37
    :cond_0
    :goto_0
    return-void
    .line 30
    :catch_0
    move-exception v0
    .line 34
    const-string v5, "debug"
    const-string v6, "file write error"
    invoke-static {v5, v6}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
    goto :goto_0
.end method

使用方法为,在要查看的寄存器vx的下方换行添加代码:

[Java] 纯文本查看 复制代码
1
invoke-static {vx}, Lcrack;->puts(Ljava/lang/String;)V

至于输出整型变量到文本,请参考之前的例子,先将整型变量转为字符串,再输出,具体代码这里略过。。。

下面介绍通过注入,改变软件获得的imei号,让软件改为读取保存在 “/sdcard/deviceid/imei.txt” 里的串号。

参考java代码如下:

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.io.*;
public class crack {
        public static String getDeviceId()
        {
        String path = "/sdcard/deviceid/imei.txt";
        String str = null;
        File f = new File(path);
        if (f != null && f.exists()) 
        {
            FileInputStream fis = null;
            try {
                    fis = new FileInputStream(f);
            } catch (FileNotFoundException e1) {
            e1.printStackTrace(); 
        }
            InputStreamReader inputStreamReader = null;
            try {
                    inputStreamReader = new InputStreamReader(fis, "utf-8");
                    try {
                            BufferedReader reader = new BufferedReader(inputStreamReader);
                            StringBuffer sb = new StringBuffer("");
                            String line;
                            line = reader.readLine();
                            sb.append(line);
                            reader.close();       
                            fis.close();
                            str = sb.toString();
                    catch (IOException e) {  
                e.printStackTrace();  
            }
            } catch (UnsupportedEncodingException e) { 
                     e.printStackTrace();          
                 }  
        }
              return str;
        }
}

反编译后得到的smali代码如下:

[Java] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
.method public static getDeviceId()Ljava/lang/String;
    .locals 13
    .prologue
    const-string v8, "/sdcard/deviceid/imei.txt"
    const/4 v11, 0x0
    new-instance v2, Ljava/io/File;
    invoke-direct {v2, v8}, Ljava/io/File;-><init>(Ljava/lang/String;)V
    if-eqz v2, :cond_0
    invoke-virtual {v2}, Ljava/io/File;->exists()Z
    move-result v12
    if-eqz v12, :cond_0
    const/4 v3, 0x0
    :try_start_0
    new-instance v4, Ljava/io/FileInputStream;
    invoke-direct {v4, v2}, Ljava/io/FileInputStream;-><init>(Ljava/io/File;)V
    :try_end_0
    .catch Ljava/io/FileNotFoundException; {:try_start_0 .. :try_end_0} :catch_0
    move-object v3, v4
    :goto_0
    const/4 v5, 0x0
    :try_start_1
    new-instance v6, Ljava/io/InputStreamReader;
    const-string v12, "utf-8"
    invoke-direct {v6, v3, v12}, Ljava/io/InputStreamReader;-><init>(Ljava/io/InputStream;Ljava/lang/String;)V
    :try_end_1
    .catch Ljava/io/UnsupportedEncodingException; {:try_start_1 .. :try_end_1} :catch_3
    :try_start_2
    new-instance v9, Ljava/io/BufferedReader;
    invoke-direct {v9, v6}, Ljava/io/BufferedReader;-><init>(Ljava/io/Reader;)V
    new-instance v10, Ljava/lang/StringBuffer;
    const-string v12, ""
    invoke-direct {v10, v12}, Ljava/lang/StringBuffer;-><init>(Ljava/lang/String;)V
    invoke-virtual {v9}, Ljava/io/BufferedReader;->readLine()Ljava/lang/String;
    move-result-object v7
    invoke-virtual {v10, v7}, Ljava/lang/StringBuffer;->append(Ljava/lang/String;)Ljava/lang/StringBuffer;
    invoke-virtual {v9}, Ljava/io/BufferedReader;->close()V
    invoke-virtual {v3}, Ljava/io/FileInputStream;->close()V
    invoke-virtual {v10}, Ljava/lang/StringBuffer;->toString()Ljava/lang/String;
    :try_end_2
    .catch Ljava/io/IOException; {:try_start_2 .. :try_end_2} :catch_1
    .catch Ljava/io/UnsupportedEncodingException; {:try_start_2 .. :try_end_2} :catch_2
    move-result-object v11
    :cond_0
    :goto_1
    return-object v11
    :catch_0
    move-exception v1
    invoke-virtual {v1}, Ljava/io/FileNotFoundException;->printStackTrace()V
    goto :goto_0
    :catch_1
    move-exception v0
    :try_start_3
    invoke-virtual {v0}, Ljava/io/IOException;->printStackTrace()V
    :try_end_3
    .catch Ljava/io/UnsupportedEncodingException; {:try_start_3 .. :try_end_3} :catch_2
    goto :goto_1
    :catch_2
    move-exception v0
    move-object v5, v6
    :goto_2
    invoke-virtual {v0}, Ljava/io/UnsupportedEncodingException;->printStackTrace()V
    goto :goto_1
    :catch_3
    move-exception v0
    goto :goto_2
.end method

使用方法为:

查找

[Java] 纯文本查看 复制代码
1
Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;

在下面换行添加

[Java] 纯文本查看 复制代码
1
invoke-static {}, Lcrack;->getDeviceId()Ljava/lang/String;

 

6Jun/14

iPhone如何打包成一个通用的静态库文件(模拟器和真机都可以用)?

Posted by Nick Xu

iPhone如何打包成一个通用的静态库文件(模拟器和真机都可以用)?

最近在做一个购票项目,支付与银联合作,他们提供2个.a的静态库文件,一个真机使用,一个是模拟器使用。但是每次真机测试的时候,都要换成真机的.a库,模拟器测试的时候又要换回来,特别麻烦。一天几十次真机和模拟器测试,来回折腾浪费了很多时间,我终于受不了,网上也没一个完整的解决方案,google了下方法,最后通过自己的实践,成功的解决了.a静态库文件通用性问题,希望这个能给大家带来方便,痛苦的童鞋们,可以解脱了!

1.先来一个必须的命令:
~/Library目录在lion下是默认隐藏的。这样很不方便。用一下命令可以使其显示:
chflags nohidden ~/Library
如果想再让其隐藏,可以:
chflags hidden ~/Library

2.静态库工程的建立:Xcode New一个新的project,选择IOS下面的Framework&Library,下面有一个Cocoa Touch Static Library。直接next去建立一个MtimeLibrary这样的工程。(里面的功能就不要关注了,简单 2个数相加)

3.工程建立以后,删除默认的.h .m 文件,然后自己创建CountNumbers..h CountNumbers..m文件。如下图:

4.OK,选择iPhone 5.1Simulator ,Command + B 编译,我们可以在Products下面找到我们编译生成一个模拟器上可运行的libMtimeLibrary.a这个文件,然后选择真机(如下图)再编译一次,这样会生成一个可以真机运行的libMtimeLibrary.a库。

5. 在libMtimeLibrary.a 右键 Open in Finder,可以找到libMtimeLibrary.a所在路径、后面我们会新建一个项目来添加这个.a文件测试。

打开终端:输入以下命令(路径根据自己的来决定)
cd /Users/cash/Library/Developer/Xcode/DerivedData/MtimeLibrary-amyqbnwwzcivnyeijggzaorseihj/Build/Products/

这样就到了Products目录下了,ls 以后可以看到:

再输入一个命令: cd Debug-iphonesimulator/

然后通过下面命令来查看libMtimeLibrary.a信息
命令:lipo -info libMtimeLibrary.a
显示:
cashmatoMacBook-Pro:Debug-iphonesimulator cash$ lipo -info libMtimeLibrary.a
input file libMtimeLibrary.a is not a fat file
Non-fat file: libMtimeLibrary.a is architecture: i386
i386是mac上的架构。

然后再输入下面命令:
cd ../

cd Debug-iphoneos/

继续通过命令来查看 lipo -info libMtimeLibrary.a,
显示:
cashmatoMacBook-Pro:Debug-iphoneos cash$ lipo -info libMtimeLibrary.a
input file libMtimeLibrary.a is not a fat file
Non-fat file: libMtimeLibrary.a is architecture: armv7
armv7是iOS上的jia'ge架构。

到这里我们也明白了,为什么一个在真机上可以使用,一个只能在模拟器上使用了吧!

最后我们要做的就是要让这个libMtimeLibrary.a文件同时有i386和armv7信息,这样就是一个通用的静态库文件了。

6. 新建一个MtimeLibraryDemo应用,然后把真机或者模拟器的libMtimeLibrary.a 和CountNumbers.h文件引入进来,如图:

添加CountNumbers.h文件到需要调用的类里面,然后就可以调用libMtimeLibrary.a里面的方法了。

//
// AppDelegate.m
// MtimeLibraryDemo
//
// Created by cash on 12-3-23.
// Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import "AppDelegate.h"
#import "CountNumbers.h"
@implementation AppDelegate

@synthesize window = _window;

- (void)dealloc
{
[_window release];
[super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.

CountNumbers *cn = [[CountNumbers alloc] init];
int count = [cn addTwoNumbers:10 :20];
NSLog(@"count:%d",count);

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}

7. OK,编译运行这个应用程序。 错误了。。这个就是这篇文档的关键了.

我们找到刚才生成真机和模拟器的libMtimeLibrary.a目录。
debug-iphoneos里面的是基于arm6 arm7编译出来的库文件。debug-iphonesimulator文件夹下面的是基于i386编译出来的文件。

10. 最后是关键步骤:

通过lipo -create 命令来合并2个静态库文件。(-output 后面的/Users/cash/Desktop/test/libMtimeLibrary.a 是合并后的路径和文件名字)

lipo -create "/Users/cash/Library/Developer/Xcode/DerivedData/MtimeLibrary-amyqbnwwzcivnyeijggzaorseihj/Build/Products/Debug-iphonesimulator/libMtimeLibrary.a" "/Users/cash/Library/Developer/Xcode/DerivedData/MtimeLibrary-amyqbnwwzcivnyeijggzaorseihj/Build/Products/Debug-iphoneos/libMtimeLibrary.a" -output "/Users/cash/Desktop/test/libMtimeLibrary.a"
成功!

最后通过命令 lipo -info libMtimeLibrary.a 可以知道这个文件已经有i386和armv7信息了。
cashmatoMacBook-Pro:test cash$ lipo -info libMtimeLibrary.a
Architectures in the fat file: libMtimeLibrary.a are: i386 armv7
cashmatoMacBook-Pro:test cash$

//银联合并成通用静态库
lipo -create "/Users/cash/Desktop/iphonesimulator/upomp_bypay/lib/libUPOMP.a" "/Users/cash/Desktop/iphoneos/upomp_bypay/lib/libUPOMP.a" -output "/Users/cash/Desktop/test/libUPOMP.a"

Tagged as: , Comments Off
22May/14

android测试之getevent/sendevent

Posted by Nick Xu

关于在android平台上捕获事件的资料互联网上已经铺天盖地,但个人觉得可用性都不太大,大部仅

针对特定设备,而对于其他设备引导性不强,故整理处本文,望对初学者有个有力的帮助:

getevent 旨在获取android设备的事件信息,具体参考详细用法(本人亦初学者一枚,无法深入解释)
sendevent 则可以向设备发送模拟事件,其中包括touch和keypress

详细用法如下:

  1. Usage: getevent [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]
  2.     -t: show time stamps
  3.     -n: don't print newlines
  4.     -s: print switch states for given bits
  5.     -S: print all switch states
  6.     -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)
  7.     -d: show HID descriptor, if available
  8.     -p: show possible events (errs, dev, name, pos. events)
  9.     -i: show all device info and possible events
  10.     -l: label event types and names in plain text
  11.     -q: quiet (clear verbosity mask)
  12.     -c: print given number of events then exit
  13.     -r: print rate events are received
  14. Usage: sendevent <device> <type> <code> <value>

首先,adb shell进入android设备,运行getevent命令得到如下信息,为各类事件的驱动设备,每部

硬件可能都不一样,可以说无规律可循,个人觉得掠过吧

  1. add device 1: /dev/input/event1
  2.   name:     "pmic8xxx_pwrkey"
  3. add device 2: /dev/input/event3
  4.   name:     "apq8064-tabla-snd-card Headset Jack"
  5. add device 3: /dev/input/event2
  6.   name:     "apq8064-tabla-snd-card Button Jack"
  7. add device 4: /dev/input/event5
  8.   name:     "gpio-keys"
  9. could not get driver version for /dev/input/mice, Not a typewriter
  10. add device 5: /dev/input/event0
  11.   name:     "atmel_mxt_ts"
  12. add device 6: /dev/input/event4
  13.   name:     "mhl_rcp"

在点击设备屏幕之后得到:

  1. /dev/input/event0: 0003 0039 000002a5
  2. /dev/input/event0: 0003 0030 00000004
  3. /dev/input/event0: 0003 0035 0000017b
  4. /dev/input/event0: 0003 0036 000001cf
  5. /dev/input/event0: 0003 003a 0000001c
  6. /dev/input/event0: 0000 0000 00000000
  7. /dev/input/event0: 0003 0039 ffffffff
  8. /dev/input/event0: 0000 0000 00000000

很难辨认,加-l参数后得到 ( getevent -l )

  1. /dev/input/event0: EV_ABS       ABS_MT_TRACKING_ID     000002a6
  2. /dev/input/event0: EV_ABS       ABS_MT_TOUCH_MAJOR   00000004
  3. /dev/input/event0: EV_ABS       ABS_MT_POSITION_X      0000017b
  4. /dev/input/event0: EV_ABS       ABS_MT_POSITION_Y      000001cf
  5. /dev/input/event0: EV_ABS       ABS_MT_PRESSURE         0000001c
  6. /dev/input/event0: EV_SYN       SYN_REPORT                  00000000
  7. /dev/input/event0: EV_ABS       ABS_MT_TRACKING_ID     ffffffff
  8. /dev/input/event0: EV_SYN       SYN_REPORT                  00000000

格式为 device: type code value,即 设备、输入设备类型、按键扫描码、附加码,具体定义可从kernel/include/linux/input.h中获得,至于这个头文件,途径之一是从google官网源码中获取:

type: 输入设备类型,在手机系统中经常使用的键盘(keyboard)和小键盘(kaypad)属于按键设
备EV_KEY,轨迹球属于相对设备EV_REL,触摸屏属于绝对设备EV_ABS
code: 按键扫描码,区别于ASCII码和SDK中KeyEvent的键码
value: 附加码,1/0 down/up

第一行:可理解为一次touch的开始
第2行:可理解为点击开始
第3行:触摸点x坐标
第4行:触摸点y坐标
第5行:可理解为触摸点大小
第6行:事件同步(点击结束)
第7行:一次touch结束
第8行:事件同步(事件结束)

一次touch此8行是必须的,如果是longTouch呢,在touch的基础上,重复若干次第2~6行,即看起
来可能是这样子:

  1. /dev/input/event0: EV_ABS       ABS_MT_TRACKING_ID     000002a6
  2. /dev/input/event0: EV_ABS       ABS_MT_TOUCH_MAJOR   00000004
  3. /dev/input/event0: EV_ABS       ABS_MT_POSITION_X      0000017b
  4. /dev/input/event0: EV_ABS       ABS_MT_POSITION_Y      000001cf
  5. /dev/input/event0: EV_ABS       ABS_MT_PRESSURE         0000001c
  6. /dev/input/event0: EV_SYN       SYN_REPORT                  00000000
  7. /dev/input/event0: EV_ABS       ABS_MT_TOUCH_MAJOR   00000004
  8. /dev/input/event0: EV_ABS       ABS_MT_POSITION_X      0000017b
  9. /dev/input/event0: EV_ABS       ABS_MT_POSITION_Y      000001cf
  10. /dev/input/event0: EV_ABS       ABS_MT_PRESSURE         0000001c
  11. /dev/input/event0: EV_SYN       SYN_REPORT                  00000000
  12. /dev/input/event0: EV_ABS       ABS_MT_TOUCH_MAJOR   00000004
  13. /dev/input/event0: EV_ABS       ABS_MT_POSITION_X      0000017b
  14. /dev/input/event0: EV_ABS       ABS_MT_POSITION_Y      000001cf
  15. /dev/input/event0: EV_ABS       ABS_MT_PRESSURE         0000001c
  16. /dev/input/event0: EV_SYN       SYN_REPORT                  00000000
  17. ......
  18. /dev/input/event0: EV_ABS       ABS_MT_TRACKING_ID     ffffffff
  19. /dev/input/event0: EV_SYN       SYN_REPORT                  00000000

如果是drag呢,在longTouch的基础上,xy坐标从起点到终点是渐变的,其他可认为一样。

对于按键,HOME为例,一目了然:

  1. /dev/input/event0: 0001 0066 00000001
  2. /dev/input/event0: 0000 0000 00000000
  3. /dev/input/event0: 0001 0066 00000000
  4. /dev/input/event0: 0000 0000 00000000
  5. /dev/input/event0: EV_KEY       KEY_HOME             DOWN
  6. /dev/input/event0: EV_SYN       SYN_REPORT          00000000
  7. /dev/input/event0: EV_KEY       KEY_HOME             UP
  8. /dev/input/event0: EV_SYN       SYN_REPORT          00000000

所以清楚了之后,使用sendevent进行事件模拟就很轻松了,关键是从input.h中获取按键对应的扫

描码,也许每个版本的系统中input.h的内容都稍有不同,这个很头疼。

值得注意的是使用getevent获取的数值都是16进制的,而sendevent使用的是10进制的,需要进行

转换。

如点击坐标: 120,254

  1. sendevent /dev/input/event1 0003 0057 00000000      <---事件开始
  2. sendevent /dev/input/event1 0003 0048 00000010      <---点击开始
  3. sendevent /dev/input/event1 0003 0058 00000070      <---  触摸范围
  4. sendevent /dev/input/event1 0003 0053 00000120      <---  x坐标
  5. sendevent /dev/input/event1 0003 0054 00000254      <---  y坐标
  6. sendevent /dev/input/event1 0000 0000 00000000      <---点击结束(同步)
  7. sendevent /dev/input/event1 0003 0057 4294967295        <---事件结束
  8. sendevent /dev/input/event1 0000 0000 00000000      <---事件同步

翻译为:
type code value
EV_ABS ABS_MT_TRACKING_ID 00000000 <---事件开始
EV_ABS ABS_MT_TOUCH_MAJOR 00000010 <---点击开始
EV_ABS ABS_MT_PRESSURE 00000070 <--- 触摸范围
EV_ABS ABS_MT_POSITION_X 00000120 <--- x坐标
EV_ABS ABS_MT_POSITION_Y 00000254 <--- y坐标
EV_SYN SYN_REPORT 00000000 <---点击结束(同步)
EV_ABS ABS_MT_TRACKING_ID 4294967295 <---事件结束
EV_SYN SYN_REPORT 00000000 <---事件同步

对于longTouch,重复几次上面提到的步骤,而drag再弄个坐标渐变。

按键方面(MENU) DOWN:1 UP:0

  1. sendevent /dev/input/event0 0001 0102 0000000001
  2. sendevent /dev/input/event0 0000 0000 0000000000
  3. sendevent /dev/input/event0 0001 0102 0000000000
  4. sendevent /dev/input/event0 0000 0000 0000000000
  5. EV_KEY       KEY_MENU             DOWN
  6. EV_SYN       SYN_REPORT         00000000
  7. EV_KEY       KEY_MENU             UP
  8. EV_SYN       SYN_REPORT         00000000

此外还可以模拟可见字符按键。

到这里是否觉得getevent好用好理解,但sendevent却超级麻烦。没关系,如果真不想用sendevent

模拟事件的话,可以转向input命令。

个人觉得这个input命令是个重量级的东东,调用时间非常长,貌似低系统版本和高系统版本的input提

供的功能还不一样,但它毕竟好用啊,如下:

  1. usage: input ...
  2.        input text <string>
  3.        input keyevent <key code number or name>
  4.        input tap <x> <y>
  5.        input swipe <x1> <y1> <x2> <y2>

可见除了longTouch无法模拟之外,其他的都很简便了

输入文本: input text abcdefg
按键 : input keyevent KEYCODE_MENU
点击 : input tap 100 300
拖拽 : input swipe 100 600 500 600

①对于文本输入,以下字符需要加 \ 进行转义:
` ' " ~ # & ( ) | \ ; < >

②对于longTouch,使用input如何模拟?

通过使用adb shell getevent,可以得到如下设备操作后的指令,具体表示的含义,可以参考网上很多的文章,这里就不再叙述


这里的0035和0036分别表示屏幕上的X坐标和Y坐标,后面的值表示具体的坐标点,通过16进制转换可以得到值1142和1527,而我手机的屏幕分辨率为800*480的,很明显两个点是完全不匹配,那如何转换呢?

在cmd中输入adb shell getevent -p

找到您的屏幕设备中0035和0036的含义,我的手机中可以看到x的值min为0,max为1172,y的值min为0,max为1900。
这样就找到您的设备的坐标具体大小值,这里计算公式如下:
x=(x-xmin)*480/(xmax-xmin) ;
y=(y-ymin)*800/(ymax-ymin);

这样算出的坐标值就跟您手机的屏幕分辨率相匹配了。
该公式是通过查看androidvncserver源码,然后反向推出的公式,目前碰到的手机min都为0,未测试过不过为0的情况,如果不为0的情况这个公式是错误的,请各位同学补充。

   
site
site