無標題文檔

Android 的 apk 包的反编译和破解初步

注:此信息仅仅是作为技术研究使用,请勿用作非法用途。同时本团队的应用已经针对破
解有了对应的措施,并保留追求责任的权利。

前些日子看到公司的应用被破解同时在论坛里流出,所以了解了下 Android 相应的应用破解原理以及过程。

首先,下载相应解开 apk 的工具包:

https://code.google.com/p/android-apktool/

下载完了以后得到个 jar 包,我们运行

java -jar apktool.jar

就可以得到它的用法。我这边直接解压缩相应的 apk 包:

java -jar apktool.jar decode origin-v1.0.apk

解压完毕以后,在本地目录就可以看到多出来个文件夹,里面包含了 apk 的原始资源等数据。

https://files.gracecode.com/2013_11_28/1385608157@640.png

其中,最重要的就是 smali 目录,它对应的是原始 Android 项目的 src 目录,也就是 Java 源文件。不过 smali 有点类似「Java 的汇编」,详细有关 smali 的信息可以在这里得到:

https://code.google.com/p/smali/

下面,比如我们已经知道原来应用注册的位置,例如 Activity 的入口,那么我们就从这里开始切入。

https://files.gracecode.com/2013_11_28/1385608119.png

我们很容易得就能得到相应的激活注册模块的方法在哪里,例如下面的 parseActive 方法就是判断 JSONObject 是否包含了注册信息。

.method public static parseActive(Lorg/json/JSONObject;)Lcn/dxy/android/medicinehelper/api/model/Active;

从大体的阅读源码来看,这个方法主要的功能就是解析服务器返回的 JSON 信息,然后根据返回判断是否注册。那么,我的思路就是修改方法,无论服务器返回什么都返回已经注册。

https://files.gracecode.com/2013_11_28/1385608183.png

看程序代码段中,有段为

.line 35
const-string v3, "active"

invoke-static {p0, v3, v4}, Lcn/dxy/sso/util/AppUtil;->getJsonBooleanValue(Lorg/json/JSONObject;Ljava/lang/String;Z)Z

move-result v1

.line 36
.local v1, active:Z
if-nez v1, :cond_0

.line 37
invoke-static {p0}, Lcn/dxy/sso/entity/ErrorType;->constructErrorBody(Lorg/json/JSONObject;)Lcn/dxy/sso/entity/ErrorType;

move-result-object v2

其中,有个语句 if-nez v1, :cond_0 很关键,因为这个语句下面就是错误信息了(v1 的值是 JSONOBject 过来的 activte 字段的内容)。那么可以判断,这个 if 就是主要判断语句,写成伪代码也就是

if (!active) {
    showError();
    return;
}

// Activited

所以我将这个判断的内容始终改成 true,查询 smali 的语法,简单的修改如下

if-eqz v1, :cond_0

也就是做了个相反的判断,虽然这样子正常的激活码就无法注册,但根据逻辑只要输入格式对应的激活码都可以激活了。

修改完成了以后我们需要重新打包成 apk 文件,这里还是要用到上述的 apktool 工具,做个相反的操作即可:

java -jar apktool.jar build <origin-v1.0-dir> new-v1.0.apk

注意,这时通过 apktool 生成的 apk 文件是没有经过签名的,直接 adb install 是无法
安装的,会报 INSTALL_PARSE_FAILED_NO_CERTIFICATES 错误。

因此,我们需要将其前面以后再安装,这里有 Google 相应的文档阐述如何签名 apk 包:

https://developer.android.com/tools/publishing/app-signing.html

当然使用了自定义前面的 apk 包以后您就无法安装和升级官方的 apk 包了。

https://files.gracecode.com/2013_11_28/1385608067@640.png

完成上述步骤了以后,我们安装打开已经经过修改的应用,发现随便输入任何激活码就可以完成本地激活了。

- eof -

Volley 使用笔记

Google I/O 2013 上就讲到了 Volley。当时并没还有在意这个类库,直到看了某项目的源代码后,发现这个东西值得推荐。

Volley 这个库的官方介绍是:

Volley is a library that makes networking for Android apps
easier and most importantly, faster.

不是很严谨的讲,Volley 就是个包含了很多封装功能的网络请求工具类。使用这个工具类有个优势就是可以节省很多在请求以及缓存方面的开发时间。

优势

相比其他网络载入类库,Volley 的优势官方主要提到如下几点:

  1. 队列网络请求,并自动合理安排何时去请求。
  2. 提供了默认的磁盘和内存等缓存(Disk Caching & Memory Caching)选项。
  3. Volley 可以做到高度自定义,它能做到的不仅仅是缓存图片等资源。
  4. Volley 相比其他的类库更方便调试和跟踪。

基本使用

引入 Volley 很简单。使用 git 下载代码到本地

git clone https://android.googlesource.com/platform/frameworks/volley

然后引入到项目中就可以使用了。

Volley 简单的来讲主要由两个类控制:

  1. Request Queue
  2. Request

Volley 的「Hello,World」示例代码:

// 实例化 Request Queue
RequestQueue queue = Volley.newRequestQueue(context);

// 实例化 Request
String url = "<remote url>";
JsonObjectRequest jsonObjRequest =
    new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {

        @Override
        public void onResponse(JSONObject response) {
            // ...
        }
    }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            // ...

        }
    });

然后剩下要做的事情就是把这个 Request 扔到 Queue 里面即可:

queue.add(jsonObjRequest);

缓存图片资源

缓存图片资源 Volley 提供了个自定义的 NetworkImageView 继承自 ImageView 。它的优势就是载入远程图片几乎可以用「傻瓜」形容,例如:

mNetworkImageView.setImageUrl(imageUrl, new ImageLoader());

其中 ImageLoader 最重要的一个参数就是 ImageLoader.ImageCache 它控制是否需要请求网络获取数据。因此,我们可以将这个 Class 配合 LruCache 以及 DiskLruCache 用来内存和磁盘缓存。

主要方法

@Override
public Bitmap getBitmap(String url) {
    Bitmap data = mLruCache.get(url);
    if (data == null) {
        try {
            data = mDiskLruCache.get(key);
            if (data != null) {
                mLruCache.put(key, data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    } 

    return data;
}

这样子,就可以很清晰得把内存缓存和磁盘缓存之间的关系建立和链接起来了。

资源&参考

- eof -

使用命令行截取 Android 设备的界面

在进行 Android 开发的时候有时候需要截图,通常我的土办法就是打开 DDMS 然后再截取,这样有点不好就是效率不高每次都需要刷新然后手工去保存。

搜索了下,发现 Linux 下已经有现成的解决方案。原理就是使用使用 Android 自带的命令行 screencap 然后通过 adb 传输过来。

整条 Shell 命令其实很简单

adb shell screencap -p | sed 's/\r$//' > outputs.png

但发现在我的 Mac 无法运行。检查了以后发现是 GNU sed 和 BSD sed 命令间有不兼容的情况。我的解决方案就是使用 brew 安装 gsed(有更好的解决方案的同学欢迎指出)。

brew install gnu-sed

然后简单得修改下上面的 Shell 脚本:

adb shell screencap -p | gsed 's/\r$//' > ~/Desktop/`date +%Y%m%d%H%M%S.png`

这样子每次运行这个脚本就能把 Android 设备的截图放到桌面了,并自动命名。

UPDATE .1

原博客的作者也给出了在 Mac 下的解决方案,他是使用 Perl :

adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png

这样子对于没有安装 brew 的同学是个好消息。

-- EOF --

又一款 Android 应用:「读知乎」

NOTE:因为没有得到「知乎」官方的许可,这款应用长期无法在国内市场上架,因此暂停开发。
同时也不保证能够正常读取「知乎」条目,在这里我表示遗憾和抱歉。

同时开放源代码,参见:https://github.com/feelinglucky/iZhihu

--

慢慢的从刷「微博」的习惯改成了刷「知乎」,相对比而言我觉得这比在「微博」上更有意义。

「读知乎」这个应用首先是 小虎 开发对应的 iOS 版,然后 小虎 说应该有个 Android 版本,刚好本人会一点点的 Android 开发,于是就有了这个应用。

Preference Screen

写这个应用没有花很多时间,甚至线框图都没有画过根据 iOS 版照葫芦画瓢就做了出来。不过慢慢的发现我需要更多的功能,然后慢慢得在正面叠加功能。

于是:

等等的这些功能是典型的个人需求驱动的开发,但愿这些繁杂的功能没有让其他使用者茫然无措。

--

从着手开发到现在已经过了两个月时间,对于某些是用过的东西有了更多的印象。在这里说下我这里的心得吧,仅仅是些个人的观点:

知乎

知乎上的内容很好,甚至我有点强迫症式的会刷知乎上的条目(好吧,我承认这是强迫症的表现之一)。

从知乎站点的页面设计上说,知乎的页面其实并不适合阅读。所以,每次阅读我感兴趣的条目时,都要「Command + +」增大字体阅读。

同时,知乎目前并没有开放的 API(据说也没有具体的计划开放 API)。这对于开发者而言非常的不友好,但知乎官方对应的「知乎」、「知乎日报」等应用都采用了知乎自己的私有接口。

其实这让「读知乎」在数据源方面的问题非常的尴尬。一方面「读知乎」的数据是取自知乎站点,并保持同步更新;另一方面,知乎没有明确的条款说明这些数据的版权以及使用方面的等问题。

BAE

「读知乎」的后台使用的是 BAE(百度应用引擎)http://developer.baidu.com/bae ,总体来讲这是个非常不错的应用平台。由于「读知乎」用户数量的增长,我们也体验了下 BAE 平台的收费服务,总体而言体验方面并不差。

对于以前传统的自己建立服务器然后写服务器端的应用,这些应用引擎提供了更加稳定和强大的空间,对此考虑以后的 B/S 应用可以尝试迁移到类似的平台,费用算起来其实并不高。

--

Main Screenshots

PS,有关源代码方面。本来是想计划开放源代码的,但由于知乎的私有接口以及其他方面的等问题,暂时就先不开源了,这里表示下抱歉。

下面是「读知乎」的下载渠道:

-- EOF --

Tab 标签,上面还是下面?

整理来自: http://www.androiduipatterns.com/2011/07/tabs-top-or-bottom.html

Android 的确成功了,但这其实这并不能说明它是成功的。例如,比较头痛的问题就是 Android 界面设计上的分裂(似乎 Android 4.0 已经有了设计规范),举个例子说明就好比标签控件(Tab)。

开始这个问题之前,我首先要表明自己的态度:我是中立者。客观意义上说我是开发设计人员,我们都想设计出让用户更容易试用的 App,就那么简单。

https://files.gracecode.com/2012_03_30/1333075710.png

回到问题本身,Tab 页标签放在上面还是放在下面其实这个问题已经争论了很久,那么我们总结下各自的观点:

放在下面

标签页在下面

  1. iPhone 应用以及其他很多应用都是这样干的,所以这样至少不会犯错
  2. 在大屏幕上(想想 Galaxy Note 吧),如果标签页放在了顶部,那么可能比较难以点击
  3. 标签页放在底部可以空出更多的内容区域

放在顶部

标签页在顶部

  1. Android 手机的物理按键(以及 4.0 的屏幕键盘)都在底部,如果标签页放在下面,将会很容易误点
  2. 这个设计源于 Web 站点顶部导航等用户已经接受的方式,同时这与 平板(Tablets)应用相对应
  3. Android 应用一直推荐试用的 Action Bar 就在顶部,因此标签页在顶部能更容易让用户操作
    4、Android 应用底部有很多弹出,例如 屏幕键盘、菜单等,如果标签页放在底部,将会被遮住

其实看得出上述的观点,原文的作者是推荐标签页放在顶部的。果然,原文的作者就针对支持 Tab 放在下面的吐了个槽:

I still find myself leaning towards top tabs. I use Sony Ericsson Arc with fairly large screen and personally I don't have any problems reaching the top of the screen for navigation (I'm aware of uselessness of anecdotal evidence and it's just my opinion).

那么这标签页到底是放在顶部还是底部呢?我个人不想在这里说服什么,您也别指望在这里能够得到结论。

有人开玩笑的说 Android 应用就像是全真七子,七个人联合起来都打不过个 iOS 应用。这个问题的部分原因就是设计师不加思索的直接将设计于 iOS 的应用 Copy 到了 Android 上面。

想想 Android 用户按下菜单键后就不能点击标签页时候的表情吧,如果你是设计师,这会儿我真担心您的人身安全 :)

-- EOF --

我的照片

嗨!我叫「明城」,八零后、技术男、伪苹果粉、微软无脑黑、宁波佬,现居杭州。

除了我的博客,同时也欢迎您访问我的 GitHubTwitterInstagram 主页。

这个 Blog 原先的名字叫 Gracecode.com 、现在叫 「無標題文檔」 。 其实无所谓叫什么名字,因为我曾经为这个名字伤透了脑筋。最后想到的这个名字都没啥特别的,说到 底是因为我实在给它不了个非常酷的名字。

如果您想联系我,可以发我邮件 echo bWluZ2NoZW5nQG91dGxvb2suY29tCg== | base64 -d

文章

项目

微信公众号