学习Frida的时候看到小肩膀视频中提到了一个apk,whyshouldipay。这个apk之前做过逆向分析修改,所以正好此处使用Frida来尝试HOOK。

逆向分析

把apk丢到jeb中,从mainfast文件。可以看到首页activity是LauncherActivity。找到首页activity,点击反编译。

1574664538019.png

从代码中可以看到,其实是做了一次网络验证,但由于时间久远,这个apk貌似是16年的CTF使用,网址现在已经不能使用了。所以需要这里进行修改,利用AK来修改smail代码。重打包安装。

.method public verifyClick(Landroid/view/View;)V
    .locals 15

    .line 39
    .restart local v1    # "b":[B
    .restart local v2    # "con":Ljava/net/URLConnection;
    .restart local v5    # "in":Ljava/io/InputStream;
    .restart local v9    # "responseBuilder":Ljava/lang/StringBuilder;
    .restart local v11    # "url":Ljava/net/URL;
    :cond_0
	
	const-string v8, "LICENSEKEYOK"

    .line 40
    #.local v8, "response":Ljava/lang/String;
    const-string v12, "LICENSEKEYOK"

    invoke-virtual {v8, v12}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v12

    if-eqz v12, :cond_1

    .line 43
    new-instance v0, Ljava/lang/String;

    invoke-direct {p0}, Lde/fraunhofer/sit/premiumapp/LauncherActivity;->getMac()Ljava/lang/String;

    move-result-object v12

    invoke-virtual {v12}, Ljava/lang/String;->getBytes()[B

    move-result-object v12

    invoke-virtual {v8}, Ljava/lang/String;->getBytes()[B

    move-result-object v13

    invoke-static {v12, v13}, Lde/fraunhofer/sit/premiumapp/MainActivity;->xor([B[B)[B

    move-result-object v12

    invoke-direct {v0, v12}, Ljava/lang/String;-><init>([B)V

    .line 44
    .local v0, "activatedKey":Ljava/lang/String;
    invoke-virtual {p0}, Lde/fraunhofer/sit/premiumapp/LauncherActivity;->getApplicationContext()Landroid/content/Context;

    move-result-object v12

    const-string v13, "preferences"

    const/4 v14, 0x0

    invoke-virtual {v12, v13, v14}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;

    move-result-object v7

    .line 45
    .local v7, "pref":Landroid/content/SharedPreferences;
    invoke-interface {v7}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor;

    move-result-object v4

    .line 46
    .local v4, "editor":Landroid/content/SharedPreferences$Editor;
    const-string v12, "KEY"

    invoke-interface {v4, v12, v0}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;

    .line 47
    invoke-interface {v4}, Landroid/content/SharedPreferences$Editor;->commit()Z

    .line 48
    new-instance v12, Landroid/support/v7/app/AlertDialog$Builder;

    invoke-direct {v12, p0}, Landroid/support/v7/app/AlertDialog$Builder;-><init>(Landroid/content/Context;)V

    const-string v13, "Activation successful"

    .line 49
    invoke-virtual {v12, v13}, Landroid/support/v7/app/AlertDialog$Builder;->setTitle(Ljava/lang/CharSequence;)Landroid/support/v7/app/AlertDialog$Builder;

    move-result-object v12

    const-string v13, "Activation successful"

    .line 50
    invoke-virtual {v12, v13}, Landroid/support/v7/app/AlertDialog$Builder;->setMessage(Ljava/lang/CharSequence;)Landroid/support/v7/app/AlertDialog$Builder;

    move-result-object v12

    const v13, 0x1080027

    .line 51
    invoke-virtual {v12, v13}, Landroid/support/v7/app/AlertDialog$Builder;->setIcon(I)Landroid/support/v7/app/AlertDialog$Builder;

    move-result-object v12

    .line 52
    invoke-virtual {v12}, Landroid/support/v7/app/AlertDialog$Builder;->show()Landroid/support/v7/app/AlertDialog;

	:cond_1
    return-void
.end method

修改如上,重新给v8寄存器赋值。并且删除以上全部请求代码,清楚其他try的代码,不然其做HTTP请求验证。完整的verifyClick函数smail代码如上。至此网络验证的给去掉了。

点击verify,就会显示验证成功,然后写入本地数据保存key值。

1574671361120.png

只不过这样修改,再点击premium的时候就是认证成功的了。

1574671432194.png

Hook 函数

那么先hook一下getMac和getKey函数,看一下返回是什么值。

import frida, sys


jscode = """

Java.perform(function(){

    var lunc = Java.use('de.fraunhofer.sit.premiumapp.LauncherActivity');
    lunc.getMac.implementation = function(){
        send("HOOK Start....");
        var sed = this.getMac();
        send(sed);
        var ser = this.getKey();
        send(ser);
        return sed;
        }
})
"""

def message(message, data):
    if message["type"] == "send":
        print("[*] {0}".format(message['payload']))
    else:
        print(message)
        
        
process = frida.get_remote_device().attach('de.fraunhofer.sit.premiumapp')
script = process.create_script(jscode)
script.on("message", message)
script.load()
sys.stdin.read()

在手机上打开Frida。转发端口27042。运行后获取到两个参数,一个是WiFi的Mac,一个是key。

1574671869395.png

然后按照修改返回参数来直接达到不修改apk的目的。

Hook 直接获得结果

从代码中就可以看到,当返回结果为LICENSEKEYOK时,调用MainActivity类下的xor方法。参数一个是上面的Mac的byte值,一个是LICENSEKEYOK的byte值。

import frida, sys


jscode = """

Java.perform(function(){
        //字符串转byte
        function stringToBytes(str) {  
            var ch, st, re = []; 
            for (var i = 0; i < str.length; i++ ) { 
                ch = str.charCodeAt(i);  // get char  
                st = [];                 // set up "stack"  
                do {  
                    st.push( ch & 0xFF );  // push byte to stack  
                    ch = ch >> 8;          // shift value down by 1 byte  
                }    
                while ( ch );  
                re = re.concat( st.reverse() ); 
            }  
            return re;  
        } 
        //byte转字符串
        function byteToString(arr) {
			if(typeof arr === 'string') {
				return arr;
			}
			var str = '',
				_arr = arr;
			for(var i = 0; i < _arr.length; i++) {
				var one = _arr[i].toString(2),
					v = one.match(/^1+?(?=0)/);
				if(v && one.length == 8) {
					var bytesLength = v[0].length;
					var store = _arr[i].toString(2).slice(7 - bytesLength);
					for(var st = 1; st < bytesLength; st++) {
						store += _arr[st + i].toString(2).slice(2);
					}
					str += String.fromCharCode(parseInt(store, 2));
					i += bytesLength - 1;
				} else {
					str += String.fromCharCode(_arr[i]);
				}
			}
			return str;
		}


    var lunc = Java.use('de.fraunhofer.sit.premiumapp.LauncherActivity');
    var main = Java.use('de.fraunhofer.sit.premiumapp.MainActivity');
    lunc.getKey.implementation = function(){
        send("HOOK Start....");
        var sed = this.getMac();
        send(sed);                   //获取mac
        var xor = main.xor(stringToBytes(sed), stringToBytes("LICENSEKEYOK"));   //生成key
        var ser = byteToString(xor);
        send(ser);
        return ser;
        }
})
"""

def message(message, data):
    if message["type"] == "send":
        print("[*] {0}".format(message['payload']))
    else:
        print(message)
        
        
process = frida.get_remote_device().attach('de.fraunhofer.sit.premiumapp')
script = process.create_script(jscode)
script.on("message", message)
script.load()
sys.stdin.read()

执行如上代码,即可Hook到key函数,然后由xor生成,来返回给getKey函数。返回如下所示。

1574673463247.png





tocToc: