진단 전
IPA 추출 (AppStore)
FlexDump (AppStore)
flexdecrypt, flexdump 설치
chmod 777 flexdecrypt
chmod 777 flexdump
dpkg -i flexdecrypt
dpkg - i flexdump
IpaInstaller
Cydia 에서 ipa installer 설치 가능
ipainstaller -b [번들식별자]
- 저장경로
/private/var/mobile/Documents
Frida Code
Frida-trace
frida-trace -U -f kr.wink.alda -m "*[*Jail* *]"
-m : 키워드 포함 클래스 출력
-M : 키워드 제외 클래스 출력
raptor_frida_ios_trace.js
// generic trace
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("*[JailbreakDetection *]")
// 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!");
}
ObjC Class & Method 확인
- Class 확인
if(ObjC.available) {
for(var classname in ObjC.classes)
console.log(classname);
}
- Method 확인
if(ObjC.available) {
var classname = "JailbreakDetection"
var methods = ObjC.classes[classname].$ownMethods
console.log(methods)
}
- 반환값 확인
if(ObjC.available) {
var classname = "JailbreakDetection"
var methodsname = "isJailbroken"
var hook = ObjC.classes[classname][methodsname]
Interceptor.attach(hook.implementation, {
onLeave: function(retval) { //반환값을 확인하기 위해서는 onLeave 사용
console.log("Class name = " + classname)
console.log("Method name = " + methodsname)
console.log("Type of return value = " + hook.returnType)
console.log("return vaule = " + retval)
}
})
}
Swift 리턴값 변경
- Return Value 변경
var realBase = Module.findBaseAddress('번들아이디');
console.log("리얼베이스 주소값 : " + realBase);
var Jailbreak_address = realBase.add('0x1cbdd0'); //변경하려는 메모리 주소
console.log("if/else 비교 주소 : " + Jailbreak_address);
Interceptor.attach(Jailbreak_address, {
onEnter: function(args) {
console.log(JSON.stringify(this.context));
this.context.x0 = 0x0
console.log(JSON.stringify(this.context));
}
})
진단
코드패치
코드패치
코드 패치 후 앱 서명
ldid -e [원본바이너리파일]
ldid -e [원본바이너리파일] > useegod.xml
chmod +x [패치바이너리파일]
ldid -Suseegod.xml [패치바이너리파일]