android软件破解的工具:
smali.jar——google官方提供,主要作用是把smali文件打包成class.dex文件
baksmali.jar——google官方提供,主要作用是把*.odex文件反编译为smali文件
apktool.jar——第三方提供?用于解析*.apk文件,生成smali文件和解析资源文件
signapk.jar——apk签名工具
ddms——ADT中的一个调试工具
破解工具的使用方法:
http://sin90lzc.iteye.com/blog/1198173
除了这些破解工具之外,还需要对smali语法有一定的了解。下面的网址对smali的语法有详细的说明:
http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html
最后,最好对Android的应用开发有一定的了解,至少对Android的四大组件有深刻的认识:Activity,Service,ContentProvider,BroadcastReceiver
Android应用程序在某些机器上不能运行、崩溃的原因不外乎以下几点:
原因一:该应用程序需要依赖于生产厂商的框架(像三星,它对android的framework做过大量的修改)
错误提示:找不到field,找不到对应的方法,找不到相应的类
解决途径:
1.在smali中尝试屏蔽掉相应的field,method,或类的调用,然后进行大量测试,确保不影响正常使用
2.反编译framework,找到缺少的field,method,类的相应smali文件,根据smali文件编写java源码。(当smali文件比较小的时候,这个方法才可行,否则尽量避免用这种方法)
3.实在无招的情况下,只能把第三方的framework的smali文件复制到自己的framework里面(非常槽糕的方法)。
4.对于应用程序需要依赖第三方低层的功能实现时,而我们的低层却没有这样的功能(比如说视频通话等),此时可以使用上面的方法一解决,也可以参考技术四。
原因二:资源文件不存在,像color,drawable,string等等的资源
错误提示:资源文件找不到
解决途径:
在技巧一中有详细说明。
原因三:应用程序需要一些函数库的支持(在目录/system/lib中缺少相应的函数库)。
错误提示:一般都会抛出UnSatisfiedException异常,后面紧跟所缺函数库的库名。
解决途径:
1.在第三方的函数库中找到对应的so文件,然后复制到自己的函数库中。
2.如果函数库与函数库之间有着各种耦合的时候,方法一可能就会不适用了(看运气呗)。这时候就只能反编译so文件了(这个是C/C++的反编译的应用了,需要再学习)
原因四:应用程序没有相应的权限
错误提示:nopermission
解决途径:
1.在AndroidMenifest.xml文件中添加<user-permision />添加相应的权限
原因五:由于应用程序本身的一些安全机制或条件判断影响程序的表现
解决途径:
1.反编译成smali文件,使用技巧三的方法跟踪程序的运行,耐心地分析程序的逻辑,找到可疑smali代码,屏蔽或修改代码。
原因六:数据库的结构不一样
错误提示:缺少某个字段或类型不匹配
场情:比如android的音乐播放器与三星的音乐播放器,它们的数据库结构由MediaProvider.apk这个包提供。然而两者在MediaProvider.apk中关于数据库结构的定义是不一样的,三星音乐播放器需要更多的字段去保存信息。
解决途径:
1.拿上面场情为例,反编译MediaProvider.apk,从smali文件中找到组件ContentProvider的定义(smali文件), 在该smali文件中找到关于SQL生成表结构的字符串(如:create table...),修改该SQL语句来适合三星音乐播放器的需要,然后重新打包回apk文件。
原因七:应用程序需要引用第三方提供商自定义的框架(比如,三星的/system/framework目录下有twframework.jar、twframework-res.apk,这个就是三星的UI框架)
错误提示:
解决途径:
1.屏蔽AndroidMenifest.xml文件中<uses-library android:name="sec_feature" />的代码,一般这样改动是不可行的。
2.在/system/etc/permission目录下添加库的声明,如添加touchwiz.xml文件,文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<permissions>
<library name="touchwiz" file="/system/framework/twframework.jar"/>
</permissions>
最后,还需要把三星的twframework.jar、twframework-res.apk复制到/system/framework目录下
反编译或破解的技巧总结:
一、对无应用程序源码的情况下,对资源文件的增删改。
概述:在无程序源码,不重新编译的情况下,删除或修改资源文件都是非常简单的一件事情,网上也有很多的文章提到过。但是网上却找不到在不重新编译的情况下添加资源文件的方法。
在不重新编译的情况下添加资源文件的步骤:
1.按正常的应用程序开发添加资源。比如,要添加一个string资源,在values/strings.xml上加上:
<string name="newstring">content</string>
2.一个编译后的apk会在values目录下多生成了一个public.xml文件,这个文件记录了每个资源的引用编号。以添加string资源为例, 在public.xml文件中找到<public type="string" ...>中最后一个元素,在这个元素后添加
<public type="string" name="newstring" id="0x7f0700a0" /><!--此时id就是string资源newstring的引用编号,注意该id应该是public.xml文件中是唯一值-->
3.修改smali文件,使用新增的资源
invoke-virtual {p0}, Lcom/sini/SfsdfsActivity;->getResources()Landroid/content/res/Resources;
move-result-object v0
const v1, 0x7f0700a0
invoke-virtual {v0, v1}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;
二、编写smali文件
概述:自己一手一脚去写smali文件是件超级困难的事情,如何快速地得到smali代码呢?
技巧:使用eclipse开发工具,新建一个Android项目,用正常的开发方式写一段java代码(这个代码就是你想在smali中完成的东西)。使 用eclipse的run->Android Application选项 生成apk文件,再把apk文件反编译,找到需要的smali代码,然后复制这段代码到需要的地方。NOTIC:复制的时候需要注意smali的变量 v0,v1...的正确性。
三、跟踪程序运行
概述:没源码=寸步难行!为了能跟踪无源码的apk程序的运行,只能辛苦地修改smali添加跟踪信息了。值得庆幸的是,android本身自带有方便的日志API(Log.i()\Log.w()...);
技巧:按技巧二的方法得到Log.i()的smali代码,然后把这段代码插入到你想跟踪信息的地方。
四、只修改smali中影响UI的代码,保留功能代码(适用于必须得把smali写回java源码的情况)
概述:这里最好的例子就是破解三星的通话界面。三星的通话界面程序Phone.apk中包含了视频通话的功能,这个功能又需要依赖三星的一些低层实现。而 我们的系统中没有视频通话的功能,也没有相应的低层实现。但Phone.apk的主要功能是打电话,而这个功能android本身就自带的。也就是说三星 的Phone.apk与android的Phone.apk的核心功能是一样的,只是UI不太一样而已。此时应该只修改smali中的影响UI的代码,屏 蔽掉
smali中对视频通话的调用。
技巧:找到程序中影响UI的Actvity,然后根据smali文件的内容,写java源码
在PHP中查找中文字符,有两种方案。
1、中文字符是gbk(gb2312)
有两种解决方法
第一种:
将PHP保存为ASCII编码,然后使用strpos查找,如:
strpos($curl_res, ‘哈哈’)
第二种:
将PHP保存为UTF-8无BOM编码,然后转换字符串编码为UTF-8,再查找,如:
$curl_res = mb_convert_encoding($curl_res, ‘utf-8′, ‘gbk’);
mb_strpos($curl_res, ‘哈哈’);
2、中文字符是UTF-8
有两种解决方法
第一种:
将PHP保存为UTF-8无BOM编码,然后使用strpos查找,如:
strpos($curl_res, ‘哈哈’)
第二种:
将PHP保存为ASCII编码,然后转换字符串编码为gbk,再查找,如:
$curl_res = mb_convert_encoding($curl_res, ‘gbk’, ‘utf-8′);
mb_strpos($curl_res, ‘哈哈’);
应该可以看出一些规律,就是:函数中的中文字符串参数的编码和PHP文件保存格式的编码一致,在使用函数时要考虑到!
我生成的那个html文件被EmEditor认为UTF-8 with Signature。而好用的那个html文件被EmEditor认为UTF-8 without Signature.
对于这两种UTF-8格式的转换,我查看了网上信息,点击记事本,EmEditor等文本编辑器的另存为,当选择了UTF-8的编码格式时,Add a Unicode Signature(BOM)这个选项被激活,只要选择上,我的文件就可以存为UTF-8 with Signature的格式。可是,问题就在于,我用java怎么让我的文件直接生成为 UTF-8 with Signature的格式。
开始上google搜索UTF-8 with Signature,BOM,Add a Unicode Signature等关键字。
http://www.unicode.org/unicode/faq/utf_bom.html#BOM
我大致了解了他们两个的区别。
Q: What is a BOM?
A: A byte order mark (BOM) consists of the character code U+FEFF at the beginning of a data stream, where it can be used as a signature defining the byte order and encoding form, primarily of unmarked plaintext files. Under some higher level protocols, use of a BOM may be mandatory (or prohibited) in the Unicode data stream defined in that protocol.
http://mindprod.com/jgloss/bom.html
BOM
Byte Order Marks are special characters at the beginning of a Unicode file to indicate whether it is big or little endian, in other words does the high or low order byte come first. These codes also tell whether the encoding is 8, 16 or 32 bit. You can recognise Unicode files by their starting byte order marks, and by the way Unicode-16 files are half zeroes and Unicode-32 files are three-quarters zeros. Unicode Endian Markers
Byte-order mark Description
EF BB BF UTF-8
FF FE UTF-16 aka UCS-2, little endian
FE FF UTF-16 aka UCS-2, big endian
00 00 FF FE UTF-32 aka UCS-4, little endian.
00 00 FE FF UTF-32 aka UCS-4, big-endian.
There are also variants of these encodings that have an implied endian marker.
Unfortunately, often applications, even Javac.exe, choke on these byte order marks. Java Readers don't automatically filter them out. There is not much you can do but manually remove them.
http://cache.baidu.com/c?word=java%2Cbom&url=http%3A//tgdem530%2Eblogchina%2Ecom/&b=0&a=1&user=baidu
c、UTF的字节序和BOM
UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。 例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是 “奎”还是“乙”?
Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:
在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。
这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。
UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。
Windows就是使用BOM来标记文本文件的编码方式的。
原来BOM是在文件的开始加了几个字节作为标记。有了这个标记,一些协议和系统才能识别。好,看看怎么加上这写字节。
终于在这里找到了
http://mindprod.com/jgloss/encoding.html
UTF-8
8-bit encoded Unicode. neé UTF8. Optional marker on front of file: EF BB BF for reading. Unfortunately, OutputStreamWriter does not automatically insert the marker on writing. Notepad can't read the file without this marker. Now the question is, how do you get that marker in there? You can't just emit the bytes EF BB BF since they will be encoded and changed. However, the solution is quite simple. prw.write( '\ufeff' ); at the head of the file. This will be encoded as EF BB BF.
DataOutputStreams have a binary length count in front of each string. Endianness does not apply to 8-bit encodings. Java DataOutputStream and ObjectOutputStream uses a slight variant of kosher UTF-8. To aid with compatibility with C in JNI, the null byte '\u0000' is encoded in 2-byte format rather than 1-byte, so that the encoded strings never have embedded nulls. Only the 1-byte, 2-byte, and 3-byte formats are used. Supplementary characters, (above 0xffff), are represented in the form of surrogate pairs (a pair of encoded 16 bit characters in a special range), rather than directly encoding the character.
prw.write( '\ufeff' );就是这个。
于是我的代码变为:
public void htmlWrite(String charsetName) {
try {
out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(outFileName), "UTF-8"));
out.write('\ufeff');
out.write(res);
out.flush();
if (out != null) {
out.close();
}
} catch (Exception e) {
try {
if (out != null) {
out.close();
}
} catch (IOException e1) {
System.out.print("write errors!" + e);
}
System.out.print("write errors!" + e);
}
}
问题解决。