[Game][AOS][FRIDA] Memory Scan

koo00·2023년 3월 20일
0

메모리 내 문자열과 데이터를 스캔할 수 있는 프리다 스크립트를 작성했다.
게임 가디언 메모리 스캔 기능과 유사하게 내가 바꾸고자 하는 값을 찾을 수 있도록 만들었다.
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 명령어로 값을 변조하고 진짜 바뀌었는지, 테스트해보면 된다.

profile
JFDI !

0개의 댓글