메모리 내 문자열과 데이터를 스캔할 수 있는 프리다 스크립트를 작성했다.
게임 가디언 메모리 스캔 기능과 유사하게 내가 바꾸고자 하는 값을 찾을 수 있도록 만들었다.
CLI 에서 실시간 값을 바꿔가며 테스트하면 된다.
Process.enumerateRangesSync()
결과 값으로 스캔하면 시간이 2억 년 걸리기 때문에 libil2cpp.so
베이스 주소의 두 자리를 따서 ranges
를 새로 정의하여 스캔 시간을 단축했다. (정확하지 않을 수 있다.)
그래서 테스트 했을 때 빠른 속도로 게임 데이터를 찾을 수 있었다.
대충 짜서 코드가 좀 더럽다.
function scan(str, mode, mem_list) {
if(typeof(str) == 'undefined') {
console.warn('\n[*] Usage : scan(str, mode, mem_list)');
console.log('str : String or Integer');
console.log('mode: 0(First Scan) or 1(Next Scan, Need mem_list)');
console.log('mem_list : First Scan\'s Return Value');
console.log('Example : var retval = scan(\'String\', 0)');
console.log('Example : var _1st_retval = scan(900, 0)');
console.log('Example : var _2nd_retval = scan(920, 1, _1st_retval)\n');
return;
}
var string = parseInt(str);
var pattern = new Array();
var retval = new Array();
var ranges = new Array();
var range = null;
var result = null;
var list = Process.enumerateRangesSync('rw-');
var il2cpp = Module.findBaseAddress('libil2cpp.so').toString().substr(0, 4);
for(var i=0; i<list.length; i++) {
if(list[i].base.toString().indexOf(il2cpp) != -1) {
ranges.push(list[i]);
}
}
if(string.toString() == 'NaN') {
string = str;
for(var i=0; i<str.length; i++) {
pattern[i] = string.charCodeAt(i).toString(16);
}
} else {
string = string.toString(16);
if(string.length % 2 == 1) {
string = '0' + string;
}
for(var i=0; i<string.length / 2; i++) {
pattern[i] = string.slice(-2 * (i + 1), string.length - (i * 2));
}
}
switch (mode) {
case 0: {
range = ranges.pop();
while(range) {
try {
result = Memory.scanSync(range.base, range.size, pattern.join(' '));
if(result.length) {
for(var i=0; i<result.length; i++) {
console.log(JSON.stringify(result[i]));
retval.push(result[i].address);
}
}
} catch (e) {}
range = ranges.pop();
}
console.error('[!] Memory scan done !');
break;
}
case 1: {
if(!mem_list.length) {
console.error('[!] mem_list not exist !');
return;
}
for(var i=0; i<mem_list.length; i++) {
try {
var count = 0;
var check = null;
result = new Uint8Array(mem_list[i].readByteArray(pattern.length));
for(var j=0; j<pattern.length; j++) {
if(result[j].toString(16).length == 1) {
check = '0' + result[j].toString(16);
} else {
check = result[j].toString(16);
}
if(check == pattern[j]) {
count++;
}
}
if(count == pattern.length) {
console.warn(mem_list[i]);
retval.push(mem_list[i]);
}
} catch (e) {}
}
break;
}
default: {
console.error('[!] Scan mode is only 0 OR 1 !');
return;
}
}
return retval;
}
간단하게 활용하는 방법이다.
첫 번째 인자에 찾고 싶은 값을 입력하고, 두번째 인자에 0을 넣을 경우 최초 검색한다.
첫 번째 스캔이 끝나고 두 번째 인자에 1을 넣고, 세 번째 인자에 최초 검색 시 확인된 리스트를 넣으면 리스트에서 첫 번째 인자에 들어간 값을 찾아서 리턴한다.
변조하고자 하는 값을 찾았으니 CLI 명령어로 값을 변조하고 진짜 바뀌었는지, 테스트해보면 된다.