본문 바로가기

해킹-보안/모바일

frida cheatsheet

반응형

 

native 모든 context 조회

console.log( JSON.stringify(this.context) )

 

특정 라이브러리 로드 후 주소값 후킹(android)

Interceptor.attach(Module.getExportByName(null, "android_dlopen_ext"), {
  onEnter(args) {
    this.path = Memory.readUtf8String(args[0]);
  },
  onLeave(retval) {
    if ( /libfoo.so/i.test(this.path) ) {
      const target = this.path.split("/").pop();
      hook(target);
    }
  },
});

function hook(lib) {
  const base_adr = Module.findBaseAddress(lib);
  console.log("lib address => ", base_adr);

  Interceptor.attach(base_adr.add(0x100000), {
    onEnter(args) {
      console.log(this.context.x0);
    },
    onLeave(retval) {},
  });
}

 

로딩되는 라이브러리 확인(android)

// 첫 번째
Interceptor.attach(Module.findExportByName(null, 'android_dlopen_ext'), {
  onEnter: function (args) {
      this.path = Memory.readUtf8String(args[0]);
      console.log(" [+] android_dlopen_ext path : " + this.path);
  },
  onLeave: function (retval) {
  }
});


// 두 번째
Java.perform(function() {
  const System = Java.use('java.lang.System');
  const Runtime = Java.use('java.lang.Runtime');
  const VMStack = Java.use('dalvik.system.VMStack');
  System.loadLibrary.implementation = function(library) {
      try {
          console.log('System.loadLibrary("' + library + '")');
          Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), library);
      } catch(ex) {
          console.log(ex);
      }
  };
});

 

특정 라이브러리 내 로딩되는 함수 확인(android)

// 라이브러리 내의 로딩되는 함수 출력
Interceptor.attach(Module.getExportByName(null, 'android_dlopen_ext'), {
    onEnter (args) {
      this.lib = Memory.readCString(args[0]);
      console.log(">>>>>>>>>>>>>>>>>");
    },
    onLeave(retval){
        var lib_new = this.lib.toString().split('/').pop();
        if (/libso/i.test(lib_new)){
            const libc = Module.findBaseAddress(this.lib);

            var app_lib = Process.findModuleByName(lib_new).enumerateExports();
            app_lib.forEach(func => {
                Interceptor.attach(func.address, {
                    onEnter(a) {
                        console.warn(func.name);
                    }
                })
            })
                
        }
        
    }
});

 

 

특정 클래스 내 로딩되는 메서드 확인

Java.perform(function () {
  var daClass = Java.use("com.test.testa");

  // 클래스의 모든 메소드 이름을 출력
  console.log("com.test.testa 클래스의 모든 메소드:");
  var methods = daClass.class.getDeclaredMethods();
  methods.forEach(function(method) {
      console.log(method.getName());
  });

  // 각 메소드가 호출될 때 로깅
  methods.forEach(function(method) {
      var methodName = method.getName();
      var overloads = daClass[methodName].overloads;
      overloads.forEach(function(overload) {
          overload.implementation = function() {
              console.log("메소드 호출: " + methodName);
              return this[methodName].apply(this, arguments);
          };
      });
  });
});

 

 

후킹 여부 확인

// (svcAddr에 후킹 대상 입력)
const base_adr = Module.findBaseAddress('app');
let svcAddr = [0x100001, 0x100002];
  svcAddr.forEach((currentElement, index, array) => {
      Interceptor.attach(base_adr.add(currentElement), {
          onEnter(a) {   // 후킹 걸리는 주소가 출력됨
              console.log('svc call addr:',currentElement.toString(16));
          }
      });
});

 

현재 실행 중인 클래스 객체 및 변수 접근

Java.perform(function () {
  var SpannableStringBuilder = Java.use("android.text.SpannableStringBuilder");
  var String = Java.use("java.lang.String");
  Java.choose("android.widget.EditText", {
    onMatch: function (instance) {
      console.log("Found instance: " + instance);
      console.log("[*] EditText RootView: " + instance.getRootView());
      console.log("[*] EditText InputType: " + instance.getInputType());
      console.log(
        "[*] EditText Text: " +
          Java.cast(instance.getText(), SpannableStringBuilder)
      );
      console.log(
        "[*] EditText Hint: " + Java.cast(instance.getHint(), String)
      );
    },
    onComplete: function () {
      console.log("[*] Finished heap search");
    },
  });
});

 

android_dlopen backtrace 결과 상세 분석

Java.perform(function () {
    // System.loadLibrary 후킹
    var System = Java.use("java.lang.System");
    var loadLibrary_original = System.loadLibrary.overload('java.lang.String');

    System.loadLibrary.implementation = function (library) {
        console.log("System.loadLibrary called with library: " + library);
        console.trace(); // 백트레이스 출력
        loadLibrary_original.call(this, library);
    };

    // Runtime.loadLibrary0 후킹
    var Runtime = Java.use("java.lang.Runtime");
    var loadLibrary0_original = Runtime.loadLibrary0.overload('java.lang.ClassLoader', 'java.lang.String');

    Runtime.loadLibrary0.implementation = function (classLoader, library) {
        console.log("Runtime.loadLibrary0 called with library: " + library);
        console.trace(); // 백트레이스 출력
        loadLibrary0_original.call(this, classLoader, library);
    };

    // Runtime.nativeLoad 후킹
    var nativeLoad_original = Runtime.nativeLoad.overload('java.lang.String', 'java.lang.ClassLoader', 'java.lang.String');

    Runtime.nativeLoad.implementation = function (libraryPath, classLoader, libraryName) {
        console.log("Runtime.nativeLoad called with libraryPath: " + libraryPath + ", libraryName: " + libraryName);
        console.trace(); // 백트레이스 출력
        return nativeLoad_original.call(this, libraryPath, classLoader, libraryName);
    };
});

 

 

루팅&탈옥 탐지 파일명 변경

const base_adr = Module.findBaseAddress('app');
const address = [0x100001,0x100002,0x100003,0x100004];
address.filter((addr) => { 
    Interceptor.attach(base_adr.add(addr), { 
        onEnter(arg) {
            if ( /cydia/i.test(this.context.x0.readCString()) )
            {
                console.log("before: ", this.context.x0.readCString());
                Memory.writeUtf8String(this.context.x0,'/Applications/xxx.app');
                console.log("After: ", this.context.x0.readCString());
            }
        }
    });
});

 

 

안티디버깅 우회

Interceptor.attach(Module.findExportByName(null, "ptrace"), {

  onEnter: function(args) {
    var content = Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\\n') + '\\n';
    console.log("[ptrace]"+args[0]);
    console.log(content);

    if(args[0] == 0x1f){
      args[0]=ptr("0x0");
      console.log("Changed Argument value! Bypassing ptrace");
    }
  },
  onLeave: function(retval) {
    if (this.flag) // passed from onEnter
      console.log("\\nretval: " + retval);
  }
});

Interceptor.attach(Module.findExportByName(null, "sysctl"), {

  onEnter: function(args) {
    //this.a = Memory.readInt(args[0]);
    //this.b = Memory.readInt(args[0].add(ptr(4)));
    //this.c = Memory.readInt(args[0].add(ptr(8)));
    this.d = Memory.readInt(args[0].add(ptr(12))); // get pid

    var pid = Process.id;
    //console.log("pid: "+pid);
    
    if(this.d == pid){
      this.kp_proc = args[2];
      console.log("[sysctl] pid: "+this.d);
    }
    else
      this.kp_proc = null;
  },
  onLeave: function(retval){

    if(this.kp_proc != null){
      console.log(Memory.readByteArray(this.kp_proc.add(30), 16));
      Memory.writeByteArray(this.kp_proc.add(33), [0x40]);
      console.log(Memory.readByteArray(this.kp_proc.add(30), 16));
      console.log('Changed Memory value! Bypassing sysctl');
    }
  }
});

Interceptor.attach(Module.findExportByName(null, "getppid"), {

  onEnter: function(args) {
    var content = Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\\n') + '\\n';
    console.log("[getppid]");
    console.log(content);
  },
  onLeave: function(retval){
    if(retval!=0x01){
      var new_retval = prt("0x01");
      retval.replace(new_retval);
      console.log("Changed return value! Bypassing getppid")
    }
  }
});

 

 

trace 및 Backtrace

// trace(ios)
> frida-trace -U -f com.co.packages -m "*[classname *]"
ex) frida-trace -U -f com.direct -m "*[* *Jailbroken]"

// backtrcae(native) - 백트레이스할 후킹 함수에 넣어줌
console.log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n\t'));

// java trace
var logContentArray = new Array();
var singlePrefix = "|-";
function uniqBy(array, key) {
  var seen = {};
  return array.filter(function (item) {
    var k = key(item);
    return seen.hasOwnProperty(k) ? false : (seen[k] = true);
  });
}

function traceClass(targetClass) {
  var hook = Java.use(targetClass);
  var methods = hook.class.getDeclaredMethods();
  hook.$dispose;

  var parsedMethods = [];
  methods.forEach(function (method) {
    parsedMethods.push(
      method
        .toString()
        .replace(targetClass + ".", "TOKEN")
        .match(/\sTOKEN(.*)\(/)[1]
    );
  });

  var targets = uniqBy(parsedMethods, JSON.stringify);
  targets.forEach(function (targetMethod) {
    traceMethod(targetClass + "." + targetMethod);
  });
}

// usage examples
function traceMethod(targetClassMethod) {
  var delim = targetClassMethod.lastIndexOf(".");
  if (delim === -1) return;

  var targetClass = targetClassMethod.slice(0, delim);
  var targetMethod = targetClassMethod.slice(
    delim + 1,
    targetClassMethod.length
  );
  var hook = Java.use(targetClass);
  var overloadCount = hook[targetMethod].overloads.length;
  console.log(
    "Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]"
  );
  for (var i = 0; i < overloadCount; i++) {
    hook[targetMethod].overloads[i].implementation = function () {
      var logContent_1 = "entered--" + targetClassMethod;
      var prefixStr = gainLogPrefix(logContentArray);
      logContentArray.push(prefixStr + logContent_1);
      console.log(prefixStr + logContent_1);

      for (var j = 0; j < arguments.length; j++) {
        var tmpLogStr = prefixStr + "arg[" + j + "]: " + arguments[j];
        console.log(tmpLogStr);
      }

      var retval = this[targetMethod].apply(this, arguments);
      var tmpReturnStr = prefixStr + "retval: " + retval;
      console.log(tmpReturnStr);
      var logContent_ex = "exiting--" + targetClassMethod;
      console.log(prefixStr + logContent_ex);
      return retval;
    };
  }
}

function gainLogPrefix(theArray) {
  var lastIndex = theArray.length - 1;
  if (lastIndex < 0) {
    return singlePrefix;
  }

  for (var i = lastIndex; i >= 0; i--) {
    var tmpLogContent = theArray[i];
    var cIndex = tmpLogContent.indexOf("entered--");
    if (cIndex == -1) {
      var cIndex2 = tmpLogContent.indexOf("exiting--");
      if (cIndex2 == -1) {
        continue;
      } else {
        var resultStr = tmpLogContent.slice(0, cIndex2);
        return resultStr;
      }
    } else {
      var resultStr = singlePrefix + tmpLogContent.slice(0, cIndex); //replace(/entered--/, "");
      return resultStr;
    }
  }
  return "";
}

setTimeout(function () {
  Java.perform(function () {
    // 클래스까지만 입력
    traceClass("com.xxx.Application");
  });
}, 0);

// =========================================================
// ios backtrace
function trace(pattern)
{
var type = (pattern.indexOf(" ") === -1) ? "module" : "objc"; // [A B]와 같이 공백이 있으면 objc, 없으면 모듈
var res = new ApiResolver(type);
var matches = res.enumerateMatchesSync(pattern);
var targets = uniqBy(matches, JSON.stringify);

targets.forEach(function(target) {
if (type === "objc")
traceObjC(target.address, target.name);
else if (type === "module")
traceModule(target.address, target.name);
});
}

// remove duplicates from array
function uniqBy(array, key)
{
var seen = {};
return array.filter(function(item) {
var k = key(item);
return seen.hasOwnProperty(k) ? false : (seen[k] = true);
});
}

// trace ObjC methods
function traceObjC(impl, name)
{
console.log("Tracing " + name);

Interceptor.attach(impl, {

onEnter: function(args) {

// debug only the intended calls
this.flag = 0;
// if (ObjC.Object(args[2]).toString() === "1234567890abcdef1234567890abcdef12345678")
this.flag = 1;

if (this.flag) {
console.warn("\n[+] entered " + name);
// print caller
console.log("\x1b[31mCaller:\x1b[0m \x1b[34m" + DebugSymbol.fromAddress(this.returnAddress) + "\x1b[0m\n");

// print args
console.log("\x1b[31margs[2]:\x1b[0m \x1b[34m" + args[2] + ", \x1b[32m" + ObjC.Object(args[2]) + "\x1b[0m")
console.log("\x1b[31margs[3]:\x1b[0m \x1b[34m" + args[3] + ", \x1b[32m" + ObjC.Object(args[3]) + "\x1b[0m")
// console.log("\x1b[31margs[4]:\x1b[0m \x1b[34m" + args[4] + ", \x1b[32m" + ObjC.Object(args[4]) + "\x1b[0m")

// print full backtrace
// console.log("\nBacktrace:\n" + Thread.backtrace(this.context, Backtracer.ACCURATE)
// .map(DebugSymbol.fromAddress).join("\n"));
}
},

onLeave: function(retval) {

if (this.flag) {
// print retval
console.log("\n\x1b[31mretval:\x1b[0m \x1b[34m" + retval + "\x1b[0m");
console.warn("[-] exiting " + name);
}
}

});
}

// trace Module functions
function traceModule(impl, name)
{
console.log("Tracing " + name);

Interceptor.attach(impl, {

onEnter: function(args) {

// debug only the intended calls
this.flag = 0;
// var filename = Memory.readCString(ptr(args[0]));
// if (filename.indexOf("Bundle") === -1 && filename.indexOf("Cache") === -1) // exclusion list
// if (filename.indexOf("my.interesting.file") !== -1) // inclusion list
this.flag = 1;

if (this.flag) {
console.warn("\n*** entered " + name);

// print backtrace
console.log("\nBacktrace:\n" + Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join("\n"));
}
},

onLeave: function(retval) {

if (this.flag) {
// print retval
console.log("\nretval: " + retval);
console.warn("\n*** exiting " + name);
}
}

});
}

// usage examples. 관심있는 클래스를 명시. 대소문자 구분
if (ObjC.available) {
trace("*[* *jail*]");
// trace("*[FireflySecurityUtil *]")
// trace("*[ *ncrypt*]");
// trace("*[* *]"); 모든 클래스 추적. 앱이 다운됨
// trace("exports:libSystem.B.dylib!CCCrypt");
// trace("exports:libSystem.B.dylib!open");
// trace("exports:*!open*");

} else {
send("error: Objective-C Runtime is not available!");
}

 

IOS logtrace

function logtrace(ctx) {
  var content =
    Thread.backtrace(ctx.context, Backtracer.ACCURATE)
      .map(DebugSymbol.fromAddress)
      .join("\n") + "\n";
  if (
    content.indexOf("SubstrateLoader") == -1 &&
    content.indexOf("JavaScriptCore") == -1 &&
    content.indexOf("FLEXing.dylib") == -1 &&
    content.indexOf("NSResolveSymlinksInPathUsingCache") == -1 &&
    content.indexOf("MediaServices") == -1 &&
    content.indexOf("bundleWithPath") == -1 &&
    content.indexOf("CoreMotion") == -1 &&
    content.indexOf("infoDictionary") == -1 &&
    content.indexOf("objectForInfoDictionaryKey") == -1
  ) {
    console.log(content);
    return true;
  }
  return false;
}
function iswhite(path) {
  if (path == null) return true;
  if (path.startsWith("/var/mobile/Containers")) return true;
  if (path.startsWith("/var/containers")) return true;
  if (path.startsWith("/var/mobile/Library")) return true;
  if (path.startsWith("/var/db")) return true;
  if (path.startsWith("/private/var/mobile")) return true;
  if (path.startsWith("/private/var/containers")) return true;
  if (path.startsWith("/private/var/mobile/Library")) return true;
  if (path.startsWith("/private/var/db")) return true;
  if (path.startsWith("/System")) return true;
  if (path.startsWith("/Library/Preferences")) return true;
  if (path.startsWith("/Library/Managed")) return true;
  if (path.startsWith("/usr")) return true;
  if (path.startsWith("/dev")) return true;
  if (path == "/AppleInternal") return true;
  if (path == "/etc/hosts") return true;
  if (path == "/Library") return true;
  if (path == "/var") return true;
  if (path == "/private/var") return true;
  if (path == "/private") return true;
  if (path == "/") return true;
  if (path == "/var/mobile") return true;
  if (path.indexOf("/containers/Bundle/Application") != -1) return true;
  return false;
}
Interceptor.attach(Module.findExportByName(null, "access"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    console.log("access " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "creat"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("creat " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "dlopen"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (!iswhite(path)) console.log("dlopen " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "dlopen_preflight"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (!iswhite(path)) console.log("dlopen_preflight " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "faccessat"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[1].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("faccessat " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "getxattr"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("getxattr " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "link"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("link " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "listxattr"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("listxattr " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "lstat"), {
  block: false,
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("lstat " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "open"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = Memory.readUtf8String(args[0]);
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("open " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "opendir"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("opendir " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "__opendir2"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("opendir2 " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "readlink"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("readlink " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "realpath"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("realpath " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "realpath$DARWIN_EXTSN"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("realpath$DARWIN_EXTSN " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "stat"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("stat " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "statfs"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("statfs " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "symlink"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var path = args[0].readUtf8String();
    if (iswhite(path)) return;
    if (logtrace(this)) console.log("symlink " + path);
  },
});
Interceptor.attach(Module.findExportByName(null, "syscall"), {
  onEnter: function (args) {
    if (args[0].isNull()) return;
    var callnum = args[0].toInt32();
    if (callnum == 180) return;
    console.log("syscall " + args[0].toInt32());
  },
});

 

 

IOS 값 조회

// 함수형 선언
-[ff01234a classname] →→→ ff01234a['- classname:'];

// 1번 형태
var className = "classname";
var methodName = "+ isJailBreak";
var hook_name = eval("ObjC.classes." + className + '["' + methodName + '"]');

// 2번 형태
var checkjail = ObjC.classes.classname;
var checkjail2 = checkjail['+ isJailBreak'];
Interceptor.attach(checkjail2.implementation, {  onEnter(a){ } });
  
// CFString 값 조회
const ret = new ObjC.Object( this.context.x0 );

// String 값 변경
ret = ObjC.classes.NSString.stringWithString_('abcd1234');

 

NSString isEqualToString 후킹(IOS)  

Interceptor.attach(ObjC.classes.NSString['- isEqualToString:'].implementation, {
    onEnter: function (args) {
        var str = new ObjC.Object(ptr(args[2])).toString()
        console.log('[+] Hooked -[NSString isEqualToString:] ->'+str);
    },onLeave: function (retval){
        console.log(retval)
    }
});

Interceptor.attach(ObjC.classes.__NSCFString['- isEqualToString:'].implementation, {
    onEnter: function (args) {
      var str = new ObjC.Object(ptr(args[2])).toString()
      console.log('[+] Hooked __NSCFString[- isEqualToString:] ->' , str);
    }
});

Interceptor.attach(ObjC.classes.NSTaggedPointerString['- isEqualToString:'].implementation, {
    onEnter: function (args) {
      var str = new ObjC.Object(ptr(args[2])).toString()
      console.log('[+] Hooked NSTaggedPointerString[- isEqualToString:] ->' , str);
}});

 

JailBreak Bypass(ios)  

// file 우회
var fileExistsAtPath = ObjC.classes.NSFileManager["- fileExistsAtPath:"];
var hideFile = 0;
var paths = [
	"/Applications/blackra1n.app",
    "/Applications/crackerxi.app",
    "/Applications/Cydia.app",
    "/Applications/FakeCarrier.app",
    "/Applications/Icy.app",
    "/Applications/IntelliScreen.app",
    "/Applications/MxTube.app",
    "/Applications/RockApp.app",
    "/Applications/SBSettings.app",
    "/Applications/WinterBoard.app",
    "/bin/bash",
    "/bin/sh",
    "/bin/su",
    "/etc/alternatives/sh",
    "/etc/apt/",
    "/etc/apt",
    "/etc/apt/sources.list.d/cydia.list",
    "/etc/apt/sources.list.d/electra.list",
    "/etc/apt/sources.list.d/sileo.sourcs",
    "/etc/apt/undecimus/undecimus.list",
    "/etc/ssh/sshd_config",
    "/jb/amfid_payload.dylib",
    "/jb/jailbreakd.plist",
    "/jb/libjailbreak.dylib",
    "/jb/lzma",
    "/jb/offsets.plists",
    "/Library/MobileSubstrate/CydiaSubstrate.dylib",
    "/Library/MobileSubstrate/DynamicLibraries/*",
    "/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist",
    "/Library/MobileSubstrate/DynamicLibraries/Veency.plist",
    "/Library/MobileSubstrate/MobileSubstrate.dylib",
    "/pguntether",
    "/private/var/cache/apt",
    "/private/var/lib/apt",
    "/private/var/lib/cydia",
    "/private/var/log/syslog",
    "/private/var/mobile/Library/SBSettings/Themes",
    "/private/var/stash",
    "/private/var/tmp/cydia.log",
    "/private/var/tmp/frida-*.dylib",
    "/private/var/Users",
    "/System/Library/LaunchDaemons/com.ikey.bbot.plist",
    "/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist",
    "/usr/bin/cycript",
    "/usr/bin/ssh",
    "/usr/bin/sshd",
    "/usr/lib/libjailbreak.dylib",
    "/usr/libexec/cydia/firmware.sh",
    "/usr/libexec/sftp-server",
    "/usr/libexec/sshd-keygen-wrapper",
    "/usr/libexec/ssh-keysign",
    "/usr/sbin/frida-server",
    "/usr/sbin/sshd",
    "/usr/share/jailbreak/injectme.plist",
    "/var/cache/apt",
    "/var/lib/apt",
    "/var/lib/cydia",
    "/var/lib/dpkg/info/mobilesubstrate.dylib",
    "/var/log/apt",
    "/var/mobile/Library/Caches/com.saurik.Cydia/sources.list",
    "/var/mobile/Media/.evasi0n7_installed",
    "/var/tmp/cydia.log",
    "/.bootstrapped_electra",
    "/.cydia_no_stash",
    "/.installed_unc0ver"
	];

Interceptor.attach(fileExistsAtPath.implementation, {
    onEnter: function(args) {
	var path = ObjC.Object(args[2]);

	if (paths.indexOf(path.toString()) > -1) {
	    console.log("Found Jailbreak Check: " + path.toString());
	    hideFile = 1;
	}},

    onLeave: function(retval) {
	if (hideFile) {
	    console.log("Return Value!!(0x0)");
	    retval.replace(0);
	    hideFile = 0;
	}}
});



// canopenurl 우회
var paths = [
     	"/Applications/Cydia.app",
     	"/Applications/blackra1n.app",
     	"/Applications/FakeCarrier.app",
     	"/Applications/Icy.app",
	"/Applications/IntelliScreen.app",
	"/Applications/MxTube.app",
	"/Applications/RockApp.app",
	"/Applications/SBSettings.app",
	"/Applications/WinterBoard.app",
	"/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist",
	"/Library/MobileSubstrate/DynamicLibraries/Veency.plist",
	"/private/var/lib/apt",
	"/private/var/lib/apt/",
	"/private/var/lib/cydia",
	"/private/var/mobile/Library/SBSettings/Themes",
	"/private/var/stash",
	"/private/var/tmp/cydia.log",
	"/System/Library/LaunchDaemons/com.ikey.bbot.plist",
	"/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist",
	"/usr/bin/sshd",
	"/usr/libexec/sftp-server",
	"/usr/sbin/sshd",
	"/etc/apt",
	"/bin/bash",
	"/Library/MobileSubstrate/MobileSubstrate.dylib"
];

try {
    var resolver = new ApiResolver('objc');

    resolver.enumerateMatches('*[* fileExistsAtPath*]', {
        onMatch: function(match) {
            var ptr = match["address"];
            Interceptor.attach(ptr, {
                onEnter: function(args) {
                    var path = ObjC.Object(args[2]).toString();
                    this.jailbreakCall = false;
                    for (var i = 0; i < paths.length; i++) {
                        if (paths[i] == path) {
                            this.jailbreakCall = true;
                        }
                    }
                },
                onLeave: function(retval) {
                    if (this.jailbreakCall) {
                        retval.replace(0x0);
                    }
                }
            });
        },
        onComplete: function() {}
    });

    resolver.enumerateMatches('*[* canOpenURL*]', {
        onMatch: function(match) {
            var ptr = match["address"];
            Interceptor.attach(ptr, {
                onEnter: function(args) {
                    var url = ObjC.Object(args[2]).toString();
                    this.jailbreakCall = false;
                    if (url.indexOf("cydia") >= 0) {
                        this.jailbreakCall = true;
                    }
                },
                onLeave: function(retval) {
                    if (this.jailbreakCall) {
                        retval.replace(0x0);
                    }
                }
            });
        },
        onComplete: function() {}
    });

    var response = {
        type: 'sucess',
        data: {
            message: "[!] Jailbreak Bypass success"
        }
    };
    send(response);
} catch (e) {
    var message = {
        type: 'exception',
        data: {
            message: '[!] Jailbreak bypass script error: '
        }
    };
    send(message);
}

 

소켓 통신 확인

// android
setTimeout(function(){
    Java.perform(function(){
    
    var sock = Java.use("java.net.Socket");
    
    // Socket.bind()
    sock.bind.implementation = function(localAddress){
    console.log("Socket.bind("+localAddress.toString()+")");
    sock.bind.call(this, localAddress);
    }
    
    // Socket.connect(endPoint)
    sock.connect.overload("java.net.SocketAddress").implementation = function(endPoint){
    console.log("Socket.connect("+endPoint.toString()+")");
    sock.connect.overload("java.net.SocketAddress").call(this, endPoint);
    }
    
    // Socket.connect(endPoint, timeout)
    sock.connect.overload("java.net.SocketAddress", "int").implementation = function(endPoint, tmout){
    console.log("Socket.connect("+endPoint.toString()+", Timeout: "+tmout+")");
    sock.connect.overload("java.net.SocketAddress", "int").call(this, endPoint, tmout);
    }
    
    // Socket.getInetAddress()
    sock.getInetAddress.implementation = function(){
    ret = sock.getInetAddress.call(this);
    console.log(ret.toString()+" Socket.getInetAddress()");
    return ret;
    }
    
    // Socket.getInputStream()
    sock.getInputStream.implementation = function(){
    console.log("Socket.getInputStream()");
    return sock.getInputStream.call(this);
    }
    
    // Socket.getOutputStream()
    sock.getOutputStream.implementation = function(){
    console.log("Socket.getOutputStream()");
    return sock.getOutputStream.call(this);
    }
    
    });
    },0);
    
    /*
    Author: secretdiary.ninja
    License: (CC BY-SA 4.0)
    * */
    
    setTimeout(function(){
    Java.perform(function(){
    
    var sock = Java.use("java.net.Socket");
    
    // socket constructors
    
    //new Socket()
    sock.$init.overload().implementation = function(){
    console.log("new Socket() called");
    this.$init.overload().call(this);
    }
    
    // new Socket(inetAddress, port)
    sock.$init.overload("java.net.InetAddress", "int").implementation = function(inetAddress, port){
    console.log("new Socket('"+inetAddress.toString()+"', "+port+") called");
    this.$init.overload("java.net.InetAddress", "int").call(this, inetAddress, port);
    }
    
    // new Socket(inetAddress address, port, localInetAddress, localPort)
    sock.$init.overload("java.net.InetAddress", "int","java.net.InetAddress", "int").implementation = function(inetAddress, port, localInet, localPort){
    console.log("new Socket(RemoteInet: '"+inetAddress.toString()+"', RemotePort"+port+", LocalInet: '"+localInet+"', LocalPort: "+localPort+") called");
    this.$init.overload("java.net.InetAddress", "int","java.net.InetAddress", "int").call(this, inetAddress, port);
    }
    
    // new Socket(Proxy)
    sock.$init.overload("java.net.Proxy").implementation = function(proxy){
    console.log("new Socket(Proxy: '"+proxy.toString()+"') called");
    this.$init.overload("java.net.Proxy").call(this, proxy);
    }
    
    // new Socket(SocketImp)
    sock.$init.overload("java.net.SocketImpl").implementation = function(si){
    console.log("new Socket(SocketImpl: '"+si.toString()+"') called");
    this.$init.overload("java.net.SocketImpl").call(this, si);
    }
    
    // new Socket(host, port, localInetAddr, localPort)
    sock.$init.overload("java.lang.String", "int", "java.net.InetAddress", "int").implementation = function(host,port, localInetAddress, localPort){
    console.log("new Socket(Host: '"+host+"', RemPort: "+port+", LocalInet: '"+localInetAddress+"', localPort: "+localPort+") called");
    this.$init.overload("java.lang.String", "int", "java.net.InetAddress", "int").call(this, si);
    }
    
    
    });
},0);




"use strict";

var connect = new NativeFunction(
  Module.findExportByName(null, "connect"),
  "int",
  ["int", "pointer", "int"]
);

Interceptor.replace(
  connect,
  new NativeCallback(
    function (sockfd, addr, addrlen) {
      console.log(sockfd, addr, addrlen);
      var buf = Memory.readByteArray(addr, addrlen);
      console.log(
        hexdump(buf, { offset: 0, length: addrlen, header: true, ansi: true })
      );
      var result = connect(sockfd, addr, addrlen);
      console.log("connect()");
      var buf = Memory.readByteArray(addr, addrlen);
      console.log(
        hexdump(buf, { offset: 0, length: addrlen, header: true, ansi: true })
      );
      return result;
    },
    "int",
    ["int", "pointer", "int"]
  )
);

function hook_HttpUrlConnection() {
  Java.perform(function () {
    // java.net.URL.URL ($init) (得到URL)
    Java.use("java.net.URL").$init.overload("java.lang.String").implementation =
      function (str) {
        var result = this.$init(str);
        console.log("result , str => ", result, str);
        return result;
      };

    //HttpURLConnection setRequestProperty 
    Java.use(
      "com.android.okhttp.internal.huc.HttpURLConnectionImpl"
    ).setRequestProperty.implementation = function (str1, str2) {
      
      var result = this.setRequestProperty(str1, str2);
      console.log(".setRequestProperty result,str1,str2->", result, str1, str2);

      return result;
    };

    Java.use(
      "com.android.okhttp.internal.huc.HttpURLConnectionImpl"
    ).setRequestMethod.implementation = function (str1) {
      var result = this.setRequestMethod(str1);
      console.log(".setRequestMethod result,str1,str2->", result, str1);
      return result;
    };
  });
}
setImmediate(hook_HttpUrlConnection);



// 공통
var sendAddress = Module.findExportByName(null, "send");
console.log("send address: " + sendAddress.toString());
Interceptor.attach(sendAddress, {
  onEnter: function (args) {
    console.log(
      Thread.backtrace(this.context, Backtracer.ACCURATE)
        .map(DebugSymbol.fromAddress)
        .join("\n\t")
    );
    console.log("buf : " + Memory.readCString(args[1]));
    // Memory.protect(sendAddress, 1028 ,'rw-');
    // Memory.writeAnsiString(args[1],"바꿀내용");
    // Memory.protect(sendAddress, 1028 ,'r--');
    // console.log("replaced buf : " + Memory.readCString(args[1]));
  },
  onLeave: function (ret) {
    console.log(ret);
  },
});

 

 

 

지문인증 우회(ios)  

var lacontext = ObjC.classes['LAContext']
var localized = lacontext['- evaluatePolicy:localizedReason:reply:']

Interceptor.attach(localized.implementation, {
    onEnter: function(args) {
        var block = new ObjC.Block(args[4]);
        var callback = block.implementation;
        block.implementation = function (error, value)  {
            console.log("Touch ID Bypass")
            const result = callback(1, null);
            return result;
        }
    }
});

 

 

클릭이벤트 후킹(android)  

var jclazz = null;
var jobj = null;

function getObjClassName(obj) {
  if (!jclazz) {
    var jclazz = Java.use("java.lang.Class");
  }
  if (!jobj) {
    var jobj = Java.use("java.lang.Object");
  }
  return jclazz.getName.call(jobj.getClass.call(obj));
}

function watch(obj, mtdName) {
  var listener_name = getObjClassName(obj);
  var target = Java.use(listener_name);
  if (!target || !mtdName in target) {
    return;
  }

  target[mtdName].overloads.forEach(function (overload) {
    overload.implementation = function () {
      console.log("[WatchEvent] " + mtdName + ": " + getObjClassName(this));
      return this[mtdName].apply(this, arguments);
    };
  });
}

function OnClickListener() {
  Java.perform(function () {
    Java.use("android.view.View").setOnClickListener.implementation = function (
      listener
    ) {
      if (listener != null) {
        watch(listener, "onClick");
      }
      return this.setOnClickListener(listener);
    };

    Java.choose("android.view.View$ListenerInfo", {
      onMatch: function (instance) {
        instance = instance.mOnClickListener.value;
        if (instance) {
          console.log("mOnClickListener name is :" + getObjClassName(instance));
          watch(instance, "onClick");
        }
      },
      onComplete: function () {},
    });
  });
}
setImmediate(OnClickListener);

 

화면 캡처 방지 비활성화(android)  

var surface_view = Java.use('android.view.SurfaceView');

var set_secure = surface_view.setSecure.overload('boolean');

set_secure.implementation = function(flag){ 
    set_secure.call(false);
};

var window = Java.use('android.view.Window');
var set_flags = window.setFlags.overload('int', 'int');

var window_manager = Java.use('android.view.WindowManager');
var layout_params = Java.use('android.view.WindowManager$LayoutParams');

set_flags.implementation = function(flags, mask){
    flags =(flags.value & ~layout_params.FLAG_SECURE.value);
    set_flags.call(this, flags, mask);
};

 

Java LOG 메서드 후킹(android)  

// console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
var Log = Java.use("android.util.Log");

Log.d.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
   console.log("Log.d() : "+a.toString()+" / "+b.toString());
   return this.d.overload('java.lang.String', 'java.lang.String').call(this, a, b);
};
Log.v.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
   console.log("Log.v() : "+a.toString()+" / "+b.toString());
   return this.v.overload('java.lang.String', 'java.lang.String').call(this, a, b);
};

Log.i.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
   console.log("Log.i() : "+a.toString()+" / "+b.toString());
   return this.i.overload('java.lang.String', 'java.lang.String').call(this, a, b);
};
Log.e.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
   console.log("Log.e() : "+a.toString()+" / "+b.toString());
   return this.e.overload('java.lang.String', 'java.lang.String').call(this, a, b);
};
Log.w.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
   console.log("Log.w() : "+a.toString()+" / "+b.toString());
   return this.w.overload('java.lang.String', 'java.lang.String').call(this, a, b);
};

 

무결성 검증 우회(Android)

// base.apk를 /data/local/tmp로 복사하고 진행
Interceptor.attach(Module.findExportByName(null, "open" ), {
    onEnter: function(args) {
        this.hooked = Boolean(0);
        this.a = Memory.readCString(ptr(args[0])).toLowerCase();  
        console.log("[+] args[0] : " + this.a);

        if (this.a.indexOf("/data/app/com.app.app") !== -1) {
            var base_path = this.a.split("/");
            var prev = "/data/app/" + base_path[3] + "/base.apk";
            if(this.a == prev) {
                const file = "/data/local/tmp/base.apk"; 
                Memory.writeUtf8String(args[0], file); 
                console.log("[+] args[0] : " + this.a);
                console.log("integrity bypass") 
            }            
        }
    
    },
    onLeave: function(retval) {
        console.log("retval : " + retval)
        return retval;
    }
});

 

Java String Build 메서드 후킹(android)  

const StringBuilder = Java.use('java.lang.StringBuilder');
StringBuilder.toString.implementation = function () {
	var retVal = this.toString();
	console.log(retVal);
	return retVal;
}

 

디렉터리 조회 함수 후킹(android)  

Interceptor.attach(Module.findExportByName(null, "opendir"), {
    onEnter: function (args) {
        console.log("* dir : "+args[0].readCString());
    },
   onLeave: function (retval) {
   }
})

Interceptor.attach(Module.findExportByName(null, "readdir"), {
    onEnter: function (args) {
    
    },
   onLeave: function (retval) {
        var str =retval.add(19);
        try{
            console.log(str.readCString());
        }
        catch(err){
            console.log(" END");
        }
   }
})

 

 

 

파일/문자열 관련 함수를 후킹하여 루팅 탐지 문자열이 존재하는지 확인(android)

let funcs = [
    { name: 'open', arg: 0},
	{ name: 'fopen', arg: 1},
    { name: 'access', arg: 0},
    { name: 'strstr', arg: 1},
    { name: 'strcmp', arg: 1},
    { name: 'strcpy', arg: 1},
    { name: 'strtok', arg: 1},
	{ name: 'system', arg: 1},
    { name: 'opendir', arg: 0},   
    { name: 'scandir', arg: 0}   
  ]; 
let dup_chk;
  
funcs.filter( (func) => {  

    Interceptor.attach(Module.findExportByName(null, func['name']), {
        onEnter: function(args) {

          this.file_name = args[ func['arg'] ].readCString();
          if ( /frida|magisk|sbin\/su|\/proc\/self\/maps/i.test(this.file_name) )
          {
            const btc= Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n\t');

            if ( btc != dup_chk )
            {
                dup_chk = btc;
                console.warn("[*] ", func['name'], "-", this.file_name);
                console.log(btc);
            }
          }
        },
        onLeave: function(retval) { }
    });
});

 

 

로딩되는 파일 경로 후킹(ios)

var fileExistsAtPath = ObjC.classes.NSFileManager["- fileExistsAtPath:"];
var hideFile = 0;

var jailbreakFiles = ["/Applications/Cydia.app",
		      "/bin/bash",
		      "/bin/sh",
		      "/etc/apt/sources.list.d/sileo.sources",
		      "/etc/apt/sillyo/sileo.sources",
		      "/Library/MobileSubstrate/MobileSubstrate.dylib",
		      "/usr/sbin/sshd",
		      "/etc/apt",
		      "/usr/bin/ssh"];

Interceptor.attach(fileExistsAtPath.implementation, {
    onEnter: function(args) {
	var path = ObjC.Object(args[2]);
      console.log(path);
	if (jailbreakFiles.indexOf(path.toString()) > -1) {
	    console.log("Checking jailbreak file: " + path.toString());
	    hideFile = 1;
	} // else { console.log("[NSFileManager fileExistsAtPath:] " + path.toString()); }

    },
    onLeave: function(retval) {
	if (hideFile) {
	    console.log("Hiding jailbreak file...");
	    retval.replace(0);
	    hideFile = 0;
	}
    }
});

 

앱 실행 시 로딩되는 모든 문자열 추출(ios)

Interceptor.attach(ObjC.classes.NSString['+ stringWithUTF8String:'].implementation, {
onEnter: function (args) {
console.log('[+] Hooked +[NSString stringWithUTF8String:] ');
},
onLeave: function (retval) {
var str = new ObjC.Object(ptr(retval)).toString()

console.log("\nBacktrace:\n" + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"));
console.log('[+] Returning [NSString stringWithUTF8String:] -> ', str);
return retval;
}
});

 

리소스 함수 후킹(android)

Java.perform(function () {
  const Resources = Java.use("android.content.res.Resources");
  const getStringMethod = Resources.getString.overload("int");
  getStringMethod.implementation = function (resId) {
    console.log("getString('" + resId.toString() + "') called");
    const ret = getStringMethod.call(this, resId);
    console.log("Value is: '" + ret + "'");
    console.log(
      Java.use("android.util.Log").getStackTraceString(
        Java.use("java.lang.Exception").$new()
      )
    );
    return ret;
  };
});

 

native 함수 재정의

 const base_adr = Module.findBaseAddress(lib);
 Interceptor.replace( base_adr.add(0x12345), new NativeCallback(
      function () {
        console.log("Bypass");
        return 0;
      }, "void", ["pointer"] ) 
);

 

특정 클래스의 모든 메소드 확인(ios)

// IOS 특정 클래스의 모든 메소드 확인
console.log("[*] Started: Find All Methods of a Specific Class");
if (ObjC.available) {
  try {
    var className = "JailbreakDetectionVC";
    var methods = eval("ObjC.classes." + className + ".$methods");
    for (var i = 0; i < methods.length; i++) {
      try {
        console.log("[-] " + methods[i]);
      } catch (err) {
        console.log("[!] Exception1: " + err.message);
      }
    }
  } catch (err) {
    console.log("[!] Exception2: " + err.message);
  }
} else {
  console.log("Objective-C Runtime is not available!");
}
console.log("[*] Completed: Find All Methods of a Specific Class");

 

open / exit native 함수 후킹(ios)

// open
var openPtr = Module.getExportByName(null, 'open');
var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
Interceptor.replace(openPtr, new NativeCallback(function (pathPtr, flags) {
  var path = pathPtr.readUtf8String();
  console.log('Opening "' + path + '"');
  var fd = open(pathPtr, flags);
  console.log('Got fd: ' + fd);
  return fd;
}, 'int', ['pointer', 'int']));

// exit
var openPtr = Module.getExportByName(null, 'exit');
  var open = new NativeFunction(openPtr, 'void', ['int']);
  Interceptor.replace(openPtr, new NativeCallback(function (flags) {
    console.log('Got fd: ');
  }, 'void', ['int']));

 

exit 함수 후킹(ios)

// 1 systemExit 함수에 후킹 걸기
if (ObjC.available)
{
    try
    {
        var example = ObjC.classes.example;
        var systemExit = example['- systemExit:'];
        var systemExitImpl = systemExit.implementation;
        systemExit.implementation = ObjC.implement(systemExit, function(handle, selector){
            console.log('muffin!');
        });
    }
    catch(err)
    {
        console.log("[!] Exception2: " + err.message);
    }
}
else
{
    console.log("Objective-C Runtime is not available!");
}

// 2 탈옥 탐지 문구도 없이 앱이 종료될 경우 exit 함수에 BackTrace 
var exit = Module.findExportByName('libSystem.B.dylib', 'exit');

Interceptor.attach(exit, {
        onEnter: function (args) {
            console.log("[*] exit Call");
            console.log('\tBacktrace:\n\t' + Thread.backtrace(this.context,
                Backtracer.ACCURATE).map(DebugSymbol.fromAddress)
                .join('\n\t'));
        },
        onLeave: function (retval) {
        }
});

// 3 위 방법이 안될경우 ida에서 exit function 검색 후 함수 원형의 return 값 주소 복사 
if (ObjC.available)
{
  const base_adr = Module.findBaseAddress('app');
  let svcAddr = [0xB329CA]; // 
    svcAddr.forEach((currentElement, index, array) => {
        Interceptor.attach(base_adr.add(currentElement), {
            onEnter(a) {   
            console.log('svc call addr:',currentElement.toString(16));
            console.log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n\t'));
            }
        });
  });
}

 

현재 앱에서 로드된 className 및 Method Name 출력(ios)

if(ObjC.available){
    Object.keys(ObjC.classes).forEach(function(className){
        console.log(className);
        var methods = eval("ObjC.classes['"+className+"'].$methods");
        for(var i = 0; i<methods.length; i++){
            console.log(methods[i]);
        }
    });
}

 

특정 메서드 실행 시 후킹(ios)

// 특정 메소드 인자 타입 및 개수 확인
var arguType = ObjC.classes['Class Name']['Method Name'].argumentTypes;
 
// 특정 메소드 리턴 값 타입 확인
var retType = ObjC.classes['Class Name']['Method Name'].returnType;

// 1. implementation

if(ObjC.available){
    console.log("Running Hooking");
    var rooting = ObjC.classes['ANSMetadata'];
    var meta = rooting['- setValueInDictionary:withKey:toObject:'];
    var metafunc = meta.implementation;
    meta.implementation = ObjC.implement(meta,function(handler, selector, arg1, arg2, arg3){
        if(ObjC.Object(arg2).toString()=="jailbroken"){
            var arg3 = ObjC.classes.NSString.stringWithString_("0");
        }
        metafunc(handler,selector,arg1, arg2, arg3);
    })
}

 

// 2. attach

if(ObjC.available){
    console.log("Running Hooking");
    var meta = ObjC.classes['ANSMetadata']['- setValueInDictionary:withKey:toObject:'];
    Interceptor.attach(meta.implementation,{
        onEnter: function(args){
            console.log("onEnter");
        },
        onLeave: function(retval){
        	retval.replace(0x1)
        }
    })    
}
var baseAddr = Module.findBaseAddress('file_name');
var sub1 = baseAddr.add(0x145214);
Interceptor.attach(sub1, {
    onEnter: function (args) {
    	console.log("sub_145214 IN");
    },
    onLeave: function (retval) {
        console.log("sub_145214 OUT");
    }
})
 

// 3. replace

var base = Module.findBaseAddress("Jailbreak");
var check = base.add(0x70EC)

Interceptor.replace(check, new NativeCallback(function(){
    console.log("Check IN");
    return 1;
},'int',[]));
 

// 4. Swift 함수 인자 및 리턴 값 변조

var base = Module.findBaseAddress("file Name")

// Show Correct Password
var sub3 = base.add(0xEFF3C)
Interceptor.attach(sub3,{
    onEnter:function(args){
        // x0 == Correct Password
        // x2 == Input Password
        console.log("Correct Password : "+this.context.x0)
        // console.log(this.context.x2)
    }
})

// Bypass Password Authentication
var sub4 = base.add(0xEFF40)
Interceptor.attach(sub4,{
    onEnter:function(args){
        this.context.x0 = 0x01
        console.log("Bypass Lock")
  }
})

 

libc.so 우회(android)

// "fopen", "system", "strstr", "strtok", "open", "access" 등..
// https://gomguk.tistory.com/52
// var dup_chk;

// Interceptor.attach(Module.findExportByName("libc.so", "access"), {
// onEnter: function(args) {

//     this.file_name = args[0].readCString();
//     if ( /frida|magisk|sbin\/su|\/proc\/self\/maps/i.test(this.file_name) )
//     {
//     const btc= Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n\t');

//         if ( btc != dup_chk )
//         {
//             dup_chk = btc;
//             //console.warn("[*] ", func['name'], "-", this.file_name);
//             //console.log(btc);
//             Memory.writeUtf8String(args[0],'/testdata');
//             console.warn("Bypass access: ",this.file_name);
//         }
//     }
// },
// onLeave: function(retval) { }
// });

// Interceptor.attach(Module.findExportByName("libc.so", "open"), {
//     onEnter: function(args) {
//         var cstr = Memory.readCString(args[0]);
//         console.log("fopen >> " + cstr)

//         if ( /frida|magisk|sbin\/su|\/proc\/self\/status/i.test(cstr) )
//         {
//             Memory.writeUtf8String(args[0],'/testdata');
//             console.warn("Bypass open: ",cstr);
//         }
//     },
//     onLeave: function(retval) {
//         //console.log("retval : ", retval);

//     }
// });

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", "com.android.rooting.apk" ]; var RootBinaries = ["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk", "rooting.apk", "Magisk", "temprootremovejb", "su-backup"];

Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {
  onEnter: function (args) {
    var path = Memory.readCString(args[0]);
    console.log("fopen >> " + path.toString());
    path = path.split("/");
    var executable = path[path.length - 1];
    var shouldFakeReturn = RootBinaries.indexOf(executable) > -1;
    if (shouldFakeReturn && path.indexOf("ahnlab") === -1) {
      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]);
    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) {},
});
Interceptor.attach(Module.findExportByName("libc.so", "strstr"), {
  onEnter: function (args) {
    var cstr = Memory.readCString(args[1]);
    console.log("strstr >> " + cstr.toString());
    var shouldFakeReturn = RootBinaries.indexOf(cstr) > -1;
    if (shouldFakeReturn) {
      Memory.writeUtf8String(args[1], "/notexists");
      send("Bypass native strstr");
    }
  },
  onLeave: function (retval) {},
});
Interceptor.attach(Module.findExportByName("libc.so", "strtok"), {
  onEnter: function (args) {
    var cstr = Memory.readCString(args[1]);
    console.log("strtok >> " + cstr.toString());
    send(cstr);
  },
  onLeave: function (retval) {},
});
Interceptor.attach(Module.findExportByName("libc.so", "open"), {
  onEnter: function (args) {
    //console.log("******** OPEN")
    var cstr = Memory.readCString(args[0]);
    console.log("fopen >> " + cstr);
  },
  onLeave: function (retval) {
    //console.log("retval : ", retval);
  },
});

Interceptor.attach(Module.findExportByName("libc.so", "access"), {
  onEnter: function (args) {
    //console.log("****** access _______")
    var cstr = Memory.readCString(args[0]);
    console.log("access >> " + cstr);
    //var checkroot = Boolean(0);
    var shouldFakeReturn = RootAccess.indexOf(cstr) > -1;
    if (shouldFakeReturn) {
      var buf = Memory.allocUtf8String("/notexists");
      //Memory.writeUtf8String(args[0], "/notexists");
      this.buf = buf;
      args[0] = buf;
      //this.checkroot = Boolean(1);
    }
  },
  onLeave: function (retval) {
    /*if(this.checkroot){ 
                retval = ptr(-1); 
              } */
    //console.log("retval : ", retval);
  },
});

 

 

환경변수를 이용한 공유라이브러리 후킹

Interceptor.attach(Module.findExportByName("libc.so", "dlsym"), {
    onEnter: function(args) {
        console.log(Memory.readUtf8String(args[1]));
    },
});

 

메모리 덤프

function hexDump(dump_addr) {
    const module_base = Module.findBaseAddress("libfoo.so");
    const dump_realaddr = module_base.add(dump_addr);
 
    console.warn("\nhexdump: " + ptr(dump_addr));
    console.log(hexdump(dump_realaddr, { offset: 0, length: 32 }));
}
hexDump(0x15038);

 

 

반응형

'해킹-보안 > 모바일' 카테고리의 다른 글

IDA 동적 디버깅 설정 - Uncrackable 2 동적 분석  (0) 2022.01.23
uncrackable level 2  (0) 2022.01.22
아이폰 Unc0ver 재탈옥  (0) 2022.01.13
uncrackable level 1  (0) 2022.01.13
IOS Fiddler HTTPS 캡쳐  (0) 2022.01.07