• 카테고리

    질문 & 답변
  • 세부 분야

    보안

  • 해결 여부

    미해결

frida --codeshare를 통한 루팅 탐지 우회 문의

21.06.09 11:26 작성 조회수 857

0

안녕하세요.

알려주신

https://codeshare.frida.re에서 코드를 확인하여 연습중입니다.

근데 rooting 우회와 ssl Pinning 탐지가 둘 다 적용되어있는 경우는 어떻게해야할지해서 여쭤봅니다.

https://codeshare.frida.re/@dzonerzy/fridantiroot/

 -> 루팅 우회 (정상 작동)

https://codeshare.frida.re/@limyout/root-detection-and--ssl-pinning/

-> 루팅우회, SSL피닝우회 

      ( 루팅 우회 작동으로 예상, SSL 탐지에서 걸리는 듯 하나 어느정도는 작동하다가 실패하는 듯)

혹시 

https://codeshare.frida.re/@dzonerzy/fridantiroot/

 -> 루팅 우회 (정상 작동)

이것과

SSL 피닝 우회가 되는 코드 2개를 사용하려하는데 잘안되는것같습니다.

혹시 방법이 없을까요?

답변 2

·

답변을 작성해보세요.

0

김태영님의 프로필

김태영

2021.07.05

안녕하세요. 보안프로젝트 김태영입니다.

답변이 많이 늦었네요.. 죄송합니다.

 

일반적으로 두 개의 우회 코드를 사용하실 때는,

Java.perform(function () { }) 안에 적어주시면 됩니다.

 

예를 들어, 아래 코드는 "FRIDA 활용-루팅 탐지 우회"와 "FRIDA 활용-암호 복호화" 기능을 한번에 묶은 것입니다. Java.perform()안에 각 기능을 하는 코드를 추가해주시면 사용 가능합니다. 

import frida, sys

jscode= """
setImmediate(function(){
	Java.perform(function() {
		console.log("[*] Hooking System.exit()");
		var exitBypass = Java.use("java.lang.System");
		exitBypass.exit.implementation = function () {
			console.log("[*] Hooking Success");
		}
    
		console.log("[*] Hooking Decrypted Secret");
		var decrypteClass = Java.use("sg.vantagepoint.a.a");
		decrypteClass.a.overload('[B','[B').implementation = function(arg1, arg2) {
			retval = this.a(arg1, arg2);
			secret = ''
			for(i=0; i<retval.length; i++) {
				secret += String.fromCharCode(retval[i]);
			}
			console.log("[*] Decrypted : " + secret);
			return retval;
		}
	})
})
"""
session = frida.get_usb_device().attach("owasp.mstg.uncrackable1")
script = session.create_script(jscode)
script.load()
sys.stdin.read()

따라서, 아래와 같이 합쳐서 사용할 수 있을거 같습니다.

Java.perform(function() {
    var RootPackages = ["com.noshufou.android.su", "com.noshufou.android.su.elite", "eu.chainfire.supersu",
        "com.koushikdutta.superuser", "com.thirdparty.superuser", "com.yellowes.su", "com.koushikdutta.rommanager",
        "com.koushikdutta.rommanager.license", "com.dimonvideo.luckypatcher", "com.chelpus.lackypatch",
        "com.ramdroid.appquarantine", "com.ramdroid.appquarantinepro", "com.devadvance.rootcloak", "com.devadvance.rootcloakplus",
        "de.robv.android.xposed.installer", "com.saurik.substrate", "com.zachspong.temprootremovejb", "com.amphoras.hidemyroot",
        "com.amphoras.hidemyrootadfree", "com.formyhm.hiderootPremium", "com.formyhm.hideroot", "me.phh.superuser",
        "eu.chainfire.supersu.pro", "com.kingouser.com"
    ];

    var RootBinaries = ["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk"];

    var RootProperties = {
        "ro.build.selinux": "1",
        "ro.debuggable": "0",
        "service.adb.root": "0",
        "ro.secure": "1"
    };

    var RootPropertiesKeys = [];

    for (var k in RootProperties) RootPropertiesKeys.push(k);

    var PackageManager = Java.use("android.app.ApplicationPackageManager");

    var Runtime = Java.use('java.lang.Runtime');

    var NativeFile = Java.use('java.io.File');

    var String = Java.use('java.lang.String');

    var SystemProperties = Java.use('android.os.SystemProperties');

    var BufferedReader = Java.use('java.io.BufferedReader');

    var ProcessBuilder = Java.use('java.lang.ProcessBuilder');

    var StringBuffer = Java.use('java.lang.StringBuffer');

    var loaded_classes = Java.enumerateLoadedClassesSync();

    send("Loaded " + loaded_classes.length + " classes!");

    var useKeyInfo = false;

    var useProcessManager = false;

    send("loaded: " + loaded_classes.indexOf('java.lang.ProcessManager'));

    if (loaded_classes.indexOf('java.lang.ProcessManager') != -1) {
        try {
            //useProcessManager = true;
            //var ProcessManager = Java.use('java.lang.ProcessManager');
        } catch (err) {
            send("ProcessManager Hook failed: " + err);
        }
    } else {
        send("ProcessManager hook not loaded");
    }

    var KeyInfo = null;

    if (loaded_classes.indexOf('android.security.keystore.KeyInfo') != -1) {
        try {
            //useKeyInfo = true;
            //var KeyInfo = Java.use('android.security.keystore.KeyInfo');
        } catch (err) {
            send("KeyInfo Hook failed: " + err);
        }
    } else {
        send("KeyInfo hook not loaded");
    }

    PackageManager.getPackageInfo.implementation = function(pname, flags) {
        var shouldFakePackage = (RootPackages.indexOf(pname) > -1);
        if (shouldFakePackage) {
            send("Bypass root check for package: " + pname);
            pname = "set.package.name.to.a.fake.one.so.we.can.bypass.it";
        }
        return this.getPackageInfo.call(this, pname, flags);
    };

    NativeFile.exists.implementation = function() {
        var name = NativeFile.getName.call(this);
        var shouldFakeReturn = (RootBinaries.indexOf(name) > -1);
        if (shouldFakeReturn) {
            send("Bypass return value for binary: " + name);
            return false;
        } else {
            return this.exists.call(this);
        }
    };

    var exec = Runtime.exec.overload('[Ljava.lang.String;');
    var exec1 = Runtime.exec.overload('java.lang.String');
    var exec2 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;');
    var exec3 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;');
    var exec4 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File');
    var exec5 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;', 'java.io.File');

    exec5.implementation = function(cmd, env, dir) {
        if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {
            var fakeCmd = "grep";
            send("Bypass " + cmd + " command");
            return exec1.call(this, fakeCmd);
        }
        if (cmd == "su") {
            var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
            send("Bypass " + cmd + " command");
            return exec1.call(this, fakeCmd);
        }
        return exec5.call(this, cmd, env, dir);
    };

    exec4.implementation = function(cmdarr, env, file) {
        for (var i = 0; i < cmdarr.length; i = i + 1) {
            var tmp_cmd = cmdarr[i];
            if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {
                var fakeCmd = "grep";
                send("Bypass " + cmdarr + " command");
                return exec1.call(this, fakeCmd);
            }

            if (tmp_cmd == "su") {
                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                send("Bypass " + cmdarr + " command");
                return exec1.call(this, fakeCmd);
            }
        }
        return exec4.call(this, cmdarr, env, file);
    };

    exec3.implementation = function(cmdarr, envp) {
        for (var i = 0; i < cmdarr.length; i = i + 1) {
            var tmp_cmd = cmdarr[i];
            if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {
                var fakeCmd = "grep";
                send("Bypass " + cmdarr + " command");
                return exec1.call(this, fakeCmd);
            }

            if (tmp_cmd == "su") {
                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                send("Bypass " + cmdarr + " command");
                return exec1.call(this, fakeCmd);
            }
        }
        return exec3.call(this, cmdarr, envp);
    };

    exec2.implementation = function(cmd, env) {
        if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {
            var fakeCmd = "grep";
            send("Bypass " + cmd + " command");
            return exec1.call(this, fakeCmd);
        }
        if (cmd == "su") {
            var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
            send("Bypass " + cmd + " command");
            return exec1.call(this, fakeCmd);
        }
        return exec2.call(this, cmd, env);
    };

    exec.implementation = function(cmd) {
        for (var i = 0; i < cmd.length; i = i + 1) {
            var tmp_cmd = cmd[i];
            if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {
                var fakeCmd = "grep";
                send("Bypass " + cmd + " command");
                return exec1.call(this, fakeCmd);
            }

            if (tmp_cmd == "su") {
                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                send("Bypass " + cmd + " command");
                return exec1.call(this, fakeCmd);
            }
        }

        return exec.call(this, cmd);
    };

    exec1.implementation = function(cmd) {
        if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {
            var fakeCmd = "grep";
            send("Bypass " + cmd + " command");
            return exec1.call(this, fakeCmd);
        }
        if (cmd == "su") {
            var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
            send("Bypass " + cmd + " command");
            return exec1.call(this, fakeCmd);
        }
        return exec1.call(this, cmd);
    };

    String.contains.implementation = function(name) {
        if (name == "test-keys") {
            send("Bypass test-keys check");
            return false;
        }
        return this.contains.call(this, name);
    };

    var get = SystemProperties.get.overload('java.lang.String');

    get.implementation = function(name) {
        if (RootPropertiesKeys.indexOf(name) != -1) {
            send("Bypass " + name);
            return RootProperties[name];
        }
        return this.get.call(this, name);
    };

    Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {
        onEnter: function(args) {
            var path = Memory.readCString(args[0]);
            path = path.split("/");
            var executable = path[path.length - 1];
            var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)
            if (shouldFakeReturn) {
                Memory.writeUtf8String(args[0], "/notexists");
                send("Bypass native fopen");
            }
        },
        onLeave: function(retval) {

        }
    });

    Interceptor.attach(Module.findExportByName("libc.so", "system"), {
        onEnter: function(args) {
            var cmd = Memory.readCString(args[0]);
            send("SYSTEM CMD: " + cmd);
            if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id") {
                send("Bypass native system: " + cmd);
                Memory.writeUtf8String(args[0], "grep");
            }
            if (cmd == "su") {
                send("Bypass native system: " + cmd);
                Memory.writeUtf8String(args[0], "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled");
            }
        },
        onLeave: function(retval) {

        }
    });

    /*

    TO IMPLEMENT:

    Exec Family

    int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);
    int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
    int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0);
    int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
    int execv(const char *path, char *const argv[]);
    int execve(const char *path, char *const argv[], char *const envp[]);
    int execvp(const char *file, char *const argv[]);
    int execvpe(const char *file, char *const argv[], char *const envp[]);

    */


    BufferedReader.readLine.implementation = function() {
        var text = this.readLine.call(this);
        if (text === null) {
            // just pass , i know it's ugly as hell but test != null won't work :(
        } else {
            var shouldFakeRead = (text.indexOf("ro.build.tags=test-keys") > -1);
            if (shouldFakeRead) {
                send("Bypass build.prop file read");
                text = text.replace("ro.build.tags=test-keys", "ro.build.tags=release-keys");
            }
        }
        return text;
    };

    var executeCommand = ProcessBuilder.command.overload('java.util.List');

    ProcessBuilder.start.implementation = function() {
        var cmd = this.command.call(this);
        var shouldModifyCommand = false;
        for (var i = 0; i < cmd.size(); i = i + 1) {
            var tmp_cmd = cmd.get(i).toString();
            if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd.indexOf("mount") != -1 || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd.indexOf("id") != -1) {
                shouldModifyCommand = true;
            }
        }
        if (shouldModifyCommand) {
            send("Bypass ProcessBuilder " + cmd);
            this.command.call(this, ["grep"]);
            return this.start.call(this);
        }
        if (cmd.indexOf("su") != -1) {
            send("Bypass ProcessBuilder " + cmd);
            this.command.call(this, ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"]);
            return this.start.call(this);
        }

        return this.start.call(this);
    };

    if (useProcessManager) {
        var ProcManExec = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File', 'boolean');
        var ProcManExecVariant = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.lang.String', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'boolean');

        ProcManExec.implementation = function(cmd, env, workdir, redirectstderr) {
            var fake_cmd = cmd;
            for (var i = 0; i < cmd.length; i = i + 1) {
                var tmp_cmd = cmd[i];
                if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {
                    var fake_cmd = ["grep"];
                    send("Bypass " + cmdarr + " command");
                }

                if (tmp_cmd == "su") {
                    var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];
                    send("Bypass " + cmdarr + " command");
                }
            }
            return ProcManExec.call(this, fake_cmd, env, workdir, redirectstderr);
        };

        ProcManExecVariant.implementation = function(cmd, env, directory, stdin, stdout, stderr, redirect) {
            var fake_cmd = cmd;
            for (var i = 0; i < cmd.length; i = i + 1) {
                var tmp_cmd = cmd[i];
                if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {
                    var fake_cmd = ["grep"];
                    send("Bypass " + cmdarr + " command");
                }

                if (tmp_cmd == "su") {
                    var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];
                    send("Bypass " + cmdarr + " command");
                }
            }
            return ProcManExecVariant.call(this, fake_cmd, env, directory, stdin, stdout, stderr, redirect);
        };
    }

    if (useKeyInfo) {
        KeyInfo.isInsideSecureHardware.implementation = function() {
            send("Bypass isInsideSecureHardware");
            return true;
        }
    }
    
    
    
/*
setImmediate(function(){
   Java.perform(function(){
      var exit_bypass = Java.use("android.content.DialogInterface.OnClickListener");
      exit_bypass.onClick.implementation = function(arg, arg2){
         console.log("[*] Exit Bypass");
      }
   })
})
*/
setImmediate(function(){
/*
      var naver = Java.use("java.lang.Object");
      naver.onCreate.implementation = function(agr) {
         console.log("1111")
      }
*/

/*      var getVDR;

      Java.choose("com.lgeha.nuts.security.module.SecurityModule",{
      onMatch : function(instance){
         getVDR = instance;
      },
      onComplete : function(){
         console.log("[*] mSecurityModule apply Success");
      }
      });
      
      getVDR.getVerifyDoneResult().implementation = function(){
         return true;
      };
*/      
   })
})

 
function SSLContext()
{
    var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
    var SSLContext = Java.use('javax.net.ssl.SSLContext');

    // build fake trust manager
    var TrustManager = Java.registerClass({
        name: 'com.sensepost.test.TrustManager',
        implements: [X509TrustManager],
        methods: {
            checkClientTrusted: function (chain, authType) {
            },
            checkServerTrusted: function (chain, authType) {
            },
            getAcceptedIssuers: function () {
                return [];
            }
        }
    });

    // pass our own custom trust manager through when requested
    var TrustManagers = [TrustManager.$new()];
    var SSLContext_init = SSLContext.init.overload(
        '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'
    );
    SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {
        console.log('! Intercepted trustmanager request');
        SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
    };

    console.log('* Setup custom trust manager');
}
    
function okhttp3()
{
    try {
        var CertificatePinner = Java.use('okhttp3.CertificatePinner');
        CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function (str) {
            console.log('! Intercepted okhttp3: ' + str);
            return;
        };

        console.log('* Setup okhttp3 pinning')
    } catch(err) {
        console.log('* Unable to hook into okhttp3 pinner')
    }

}

function trustkit()
{
    try {
        var Activity = Java.use("com.datatheorem.android.trustkit.pinning.OkHostnameVerifier");
        Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (str) {
            console.log('! Intercepted trustkit{1}: ' + str);
            return true;
        };

        Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (str) {
            console.log('! Intercepted trustkit{2}: ' + str);
            return true;
        };

        console.log('* Setup trustkit pinning')
    } catch(err) {
        console.log('* Unable to hook into trustkit pinner')
    }

}

function TrustManagerImpl()
{
    try {
        var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
        TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
            console.log('! Intercepted TrustManagerImp: ' + host);
            return untrustedChain;
        }
      
      var ArrayList = Java.use("java.util.ArrayList");
      TrustManagerImpl.checkTrustedRecursive.implementation = function(certs, host, clientAuth, untrustedChain,
        trustAnchorChain, used) {
        console.log("[+] Bypassing TrustManagerImpl->checkTrustedRecursive()");
        return ArrayList.$new();
    };

        console.log('* Setup TrustManagerImpl pinning')
    } catch (err) {
        console.log('* Unable to hook into TrustManagerImpl')
    }

}

function Appcelerator()
{
    try {
        var PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
        PinningTrustManager.checkServerTrusted.implementation = function () {
            console.log('! Intercepted Appcelerator');
        }

        console.log('* Setup Appcelerator pinning')
    } catch (err) {
        console.log('* Unable to hook into Appcelerator pinning')
    }
}

Java.perform(function () {
    console.log("");
    console.log("[*] Universal SSL Bypass");
    console.log("[1] javax.net.ssl.SSLContext.init()");
    console.log("[2] okhttp3.CertificatePinner.check()");
    console.log("[3] com.datatheorem.android.trustkit.pinning.OkHostnameVerifier.verify()");
    console.log("[4] com.android.org.conscrypt.TrustManagerImpl.verifyChain()");
    console.log("[5] appcelerator.https.PinningTrustManager.checkServerTrusted()");
    console.log("");

    //TODO: TrustManagerImpl.checkTrustedRecursive()

    SSLContext();
    okhttp3();
    trustkit();
    TrustManagerImpl();
    Appcelerator();

    var RootPackages = [
        "com.noshufou.android.su",
        "com.noshufou.android.su.elite",
        "eu.chainfire.supersu",
        "com.koushikdutta.superuser",
        "com.thirdparty.superuser",
        "com.yellowes.su",
        "com.koushikdutta.rommanager",
        "com.koushikdutta.rommanager.license",
        "com.dimonvideo.luckypatcher",
        "com.chelpus.lackypatch",
        "com.ramdroid.appquarantine",
        "com.ramdroid.appquarantinepro",
        "com.devadvance.rootcloak",
        "com.devadvance.rootcloakplus",
        "de.robv.android.xposed.installer",
        "com.saurik.substrate",
        "com.zachspong.temprootremovejb",
        "com.amphoras.hidemyroot",
        "com.amphoras.hidemyrootadfree",
        "com.formyhm.hiderootPremium",
        "com.formyhm.hideroot",
        "me.phh.superuser",
        "eu.chainfire.supersu.pro",
        "com.kingouser.com",
      ];
    
      var RootBinaries = [
        "su",
        "busybox",
        "supersu",
        "Superuser.apk",
        "KingoUser.apk",
        "SuperSu.apk",
      ];
    
      var RootProperties = {
        "ro.build.selinux": "1",
        "ro.debuggable": "0",
        "service.adb.root": "0",
        "ro.secure": "1",
      };
    
      var RootPropertiesKeys = [];
    
      for (var k in RootProperties) RootPropertiesKeys.push(k);
    
      var PackageManager = Java.use("android.app.ApplicationPackageManager");
    
      var Runtime = Java.use("java.lang.Runtime");
    
      var NativeFile = Java.use("java.io.File");
    
      var String = Java.use("java.lang.String");
    
      var SystemProperties = Java.use("android.os.SystemProperties");
    
      var BufferedReader = Java.use("java.io.BufferedReader");
    
      var ProcessBuilder = Java.use("java.lang.ProcessBuilder");
    
      var StringBuffer = Java.use("java.lang.StringBuffer");
    
      var loaded_classes = Java.enumerateLoadedClassesSync();
    
      send("Loaded " + loaded_classes.length + " classes!");
    
      var useKeyInfo = false;
    
      var useProcessManager = false;
    
      send("loaded: " + loaded_classes.indexOf("java.lang.ProcessManager"));
    
      if (loaded_classes.indexOf("java.lang.ProcessManager") != -1) {
        try {
          //useProcessManager = true;
          //var ProcessManager = Java.use('java.lang.ProcessManager');
        } catch (err) {
          send("ProcessManager Hook failed: " + err);
        }
      } else {
        send("ProcessManager hook not loaded");
      }
    
      var KeyInfo = null;
    
      if (loaded_classes.indexOf("android.security.keystore.KeyInfo") != -1) {
        try {
          //useKeyInfo = true;
          //var KeyInfo = Java.use('android.security.keystore.KeyInfo');
        } catch (err) {
          send("KeyInfo Hook failed: " + err);
        }
      } else {
        send("KeyInfo hook not loaded");
      }
    
      PackageManager.getPackageInfo.implementation = function (pname, flags) {
        var shouldFakePackage = RootPackages.indexOf(pname) > -1;
        if (shouldFakePackage) {
          send("Bypass root check for package: " + pname);
          pname = "set.package.name.to.a.fake.one.so.we.can.bypass.it";
        }
        return this.getPackageInfo.call(this, pname, flags);
      };
    
      NativeFile.exists.implementation = function () {
        var name = NativeFile.getName.call(this);
        var shouldFakeReturn = RootBinaries.indexOf(name) > -1;
        if (shouldFakeReturn) {
          send("Bypass return value for binary: " + name);
          return false;
        } else {
          return this.exists.call(this);
        }
      };
    
      var exec = Runtime.exec.overload("[Ljava.lang.String;");
      var exec1 = Runtime.exec.overload("java.lang.String");
      var exec2 = Runtime.exec.overload("java.lang.String", "[Ljava.lang.String;");
      var exec3 = Runtime.exec.overload(
        "[Ljava.lang.String;",
        "[Ljava.lang.String;"
      );
      var exec4 = Runtime.exec.overload(
        "[Ljava.lang.String;",
        "[Ljava.lang.String;",
        "java.io.File"
      );
      var exec5 = Runtime.exec.overload(
        "java.lang.String",
        "[Ljava.lang.String;",
        "java.io.File"
      );
    
      exec5.implementation = function (cmd, env, dir) {
        if (
          cmd.indexOf("getprop") != -1 ||
          cmd == "mount" ||
          cmd.indexOf("build.prop") != -1 ||
          cmd == "id" ||
          cmd == "sh"
        ) {
          var fakeCmd = "grep";
          send("Bypass " + cmd + " command");
          return exec1.call(this, fakeCmd);
        }
        if (cmd == "su") {
          var fakeCmd =
            "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
          send("Bypass " + cmd + " command");
          return exec1.call(this, fakeCmd);
        }
        return exec5.call(this, cmd, env, dir);
      };
    
      exec4.implementation = function (cmdarr, env, file) {
        for (var i = 0; i < cmdarr.length; i = i + 1) {
          var tmp_cmd = cmdarr[i];
          if (
            tmp_cmd.indexOf("getprop") != -1 ||
            tmp_cmd == "mount" ||
            tmp_cmd.indexOf("build.prop") != -1 ||
            tmp_cmd == "id" ||
            tmp_cmd == "sh"
          ) {
            var fakeCmd = "grep";
            send("Bypass " + cmdarr + " command");
            return exec1.call(this, fakeCmd);
          }
    
          if (tmp_cmd == "su") {
            var fakeCmd =
              "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
            send("Bypass " + cmdarr + " command");
            return exec1.call(this, fakeCmd);
          }
        }
        return exec4.call(this, cmdarr, env, file);
      };
    
      exec3.implementation = function (cmdarr, envp) {
        for (var i = 0; i < cmdarr.length; i = i + 1) {
          var tmp_cmd = cmdarr[i];
          if (
            tmp_cmd.indexOf("getprop") != -1 ||
            tmp_cmd == "mount" ||
            tmp_cmd.indexOf("build.prop") != -1 ||
            tmp_cmd == "id" ||
            tmp_cmd == "sh"
          ) {
            var fakeCmd = "grep";
            send("Bypass " + cmdarr + " command");
            return exec1.call(this, fakeCmd);
          }
    
          if (tmp_cmd == "su") {
            var fakeCmd =
              "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
            send("Bypass " + cmdarr + " command");
            return exec1.call(this, fakeCmd);
          }
        }
        return exec3.call(this, cmdarr, envp);
      };
    
      exec2.implementation = function (cmd, env) {
        if (
          cmd.indexOf("getprop") != -1 ||
          cmd == "mount" ||
          cmd.indexOf("build.prop") != -1 ||
          cmd == "id" ||
          cmd == "sh"
        ) {
          var fakeCmd = "grep";
          send("Bypass " + cmd + " command");
          return exec1.call(this, fakeCmd);
        }
        if (cmd == "su") {
          var fakeCmd =
            "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
          send("Bypass " + cmd + " command");
          return exec1.call(this, fakeCmd);
        }
        return exec2.call(this, cmd, env);
      };
    
      exec.implementation = function (cmd) {
        for (var i = 0; i < cmd.length; i = i + 1) {
          var tmp_cmd = cmd[i];
          if (
            tmp_cmd.indexOf("getprop") != -1 ||
            tmp_cmd == "mount" ||
            tmp_cmd.indexOf("build.prop") != -1 ||
            tmp_cmd == "id" ||
            tmp_cmd == "sh"
          ) {
            var fakeCmd = "grep";
            send("Bypass " + cmd + " command");
            return exec1.call(this, fakeCmd);
          }
    
          if (tmp_cmd == "su") {
            var fakeCmd =
              "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
            send("Bypass " + cmd + " command");
            return exec1.call(this, fakeCmd);
          }
        }
    
        return exec.call(this, cmd);
      };
    
      exec1.implementation = function (cmd) {
        if (
          cmd.indexOf("getprop") != -1 ||
          cmd == "mount" ||
          cmd.indexOf("build.prop") != -1 ||
          cmd == "id" ||
          cmd == "sh"
        ) {
          var fakeCmd = "grep";
          send("Bypass " + cmd + " command");
          return exec1.call(this, fakeCmd);
        }
        if (cmd == "su") {
          var fakeCmd =
            "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
          send("Bypass " + cmd + " command");
          return exec1.call(this, fakeCmd);
        }
        return exec1.call(this, cmd);
      };
    
      String.contains.implementation = function (name) {
        if (name == "test-keys") {
          send("Bypass test-keys check");
          return false;
        }
        return this.contains.call(this, name);
      };
    
      var get = SystemProperties.get.overload("java.lang.String");
    
      get.implementation = function (name) {
        if (RootPropertiesKeys.indexOf(name) != -1) {
          send("Bypass " + name);
          return RootProperties[name];
        }
        return this.get.call(this, name);
      };
    
      Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {
        onEnter: function (args) {
          var path = Memory.readCString(args[0]);
          path = path.split("/");
          var executable = path[path.length - 1];
          var shouldFakeReturn = RootBinaries.indexOf(executable) > -1;
          if (shouldFakeReturn) {
            Memory.writeUtf8String(args[0], "/notexists");
            send("Bypass native fopen");
          }
        },
        onLeave: function (retval) {},
      });
    
      Interceptor.attach(Module.findExportByName("libc.so", "system"), {
        onEnter: function (args) {
          var cmd = Memory.readCString(args[0]);
          send("SYSTEM CMD: " + cmd);
          if (
            cmd.indexOf("getprop") != -1 ||
            cmd == "mount" ||
            cmd.indexOf("build.prop") != -1 ||
            cmd == "id"
          ) {
            send("Bypass native system: " + cmd);
            Memory.writeUtf8String(args[0], "grep");
          }
          if (cmd == "su") {
            send("Bypass native system: " + cmd);
            Memory.writeUtf8String(
              args[0],
              "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"
            );
          }
        },
        onLeave: function (retval) {},
      });
    
      /*
    
        TO IMPLEMENT:
    
        Exec Family
    
        int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);
        int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
        int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0);
        int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
        int execv(const char *path, char *const argv[]);
        int execve(const char *path, char *const argv[], char *const envp[]);
        int execvp(const char *file, char *const argv[]);
        int execvpe(const char *file, char *const argv[], char *const envp[]);
    
        */
    
      BufferedReader.readLine.implementation = function () {
        var text = this.readLine.call(this);
        if (text === null) {
          // just pass , i know it's ugly as hell but test != null won't work :(
        } else {
          var shouldFakeRead = text.indexOf("ro.build.tags=test-keys") > -1;
          if (shouldFakeRead) {
            send("Bypass build.prop file read");
            text = text.replace(
              "ro.build.tags=test-keys",
              "ro.build.tags=release-keys"
            );
          }
        }
        return text;
      };
    
      var executeCommand = ProcessBuilder.command.overload("java.util.List");
    
      ProcessBuilder.start.implementation = function () {
        var cmd = this.command.call(this);
        var shouldModifyCommand = false;
        for (var i = 0; i < cmd.size(); i = i + 1) {
          var tmp_cmd = cmd.get(i).toString();
          if (
            tmp_cmd.indexOf("getprop") != -1 ||
            tmp_cmd.indexOf("mount") != -1 ||
            tmp_cmd.indexOf("build.prop") != -1 ||
            tmp_cmd.indexOf("id") != -1
          ) {
            shouldModifyCommand = true;
          }
        }
        if (shouldModifyCommand) {
          send("Bypass ProcessBuilder " + cmd);
          this.command.call(this, ["grep"]);
          return this.start.call(this);
        }
        if (cmd.indexOf("su") != -1) {
          send("Bypass ProcessBuilder " + cmd);
          this.command.call(this, [
            "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled",
          ]);
          return this.start.call(this);
        }
    
        return this.start.call(this);
      };
    
      if (useProcessManager) {
        var ProcManExec = ProcessManager.exec.overload(
          "[Ljava.lang.String;",
          "[Ljava.lang.String;",
          "java.io.File",
          "boolean"
        );
        var ProcManExecVariant = ProcessManager.exec.overload(
          "[Ljava.lang.String;",
          "[Ljava.lang.String;",
          "java.lang.String",
          "java.io.FileDescriptor",
          "java.io.FileDescriptor",
          "java.io.FileDescriptor",
          "boolean"
        );
    
        ProcManExec.implementation = function (cmd, env, workdir, redirectstderr) {
          var fake_cmd = cmd;
          for (var i = 0; i < cmd.length; i = i + 1) {
            var tmp_cmd = cmd[i];
            if (
              tmp_cmd.indexOf("getprop") != -1 ||
              tmp_cmd == "mount" ||
              tmp_cmd.indexOf("build.prop") != -1 ||
              tmp_cmd == "id"
            ) {
              var fake_cmd = ["grep"];
              send("Bypass " + cmdarr + " command");
            }
    
            if (tmp_cmd == "su") {
              var fake_cmd = [
                "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled",
              ];
              send("Bypass " + cmdarr + " command");
            }
          }
          return ProcManExec.call(this, fake_cmd, env, workdir, redirectstderr);
        };
    
        ProcManExecVariant.implementation = function (
          cmd,
          env,
          directory,
          stdin,
          stdout,
          stderr,
          redirect
        ) {
          var fake_cmd = cmd;
          for (var i = 0; i < cmd.length; i = i + 1) {
            var tmp_cmd = cmd[i];
            if (
              tmp_cmd.indexOf("getprop") != -1 ||
              tmp_cmd == "mount" ||
              tmp_cmd.indexOf("build.prop") != -1 ||
              tmp_cmd == "id"
            ) {
              var fake_cmd = ["grep"];
              send("Bypass " + cmdarr + " command");
            }
    
            if (tmp_cmd == "su") {
              var fake_cmd = [
                "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled",
              ];
              send("Bypass " + cmdarr + " command");
            }
          }
          return ProcManExecVariant.call(
            this,
            fake_cmd,
            env,
            directory,
            stdin,
            stdout,
            stderr,
            redirect
          );
        };
      }
    
      if (useKeyInfo) {
        KeyInfo.isInsideSecureHardware.implementation = function () {
          send("Bypass isInsideSecureHardware");
          return true;
        };
      }

});

0

2mlnho님의 프로필

2mlnho

질문자

2021.06.09

글을 다시 읽어보니 너무 난잡한 질문인것 같습니다.

 결론은

SSL 피닝코드, root 탐지 코드를 둘 다 사용하여 우회할 수 있을까요?