**결론**: "타입에러 낫 어 펑션" 오류는 JavaScript 문법 문제입니다. Frida JavaScript 환경에 맞게 수정한 스크립트를 제공합니다.
## 🛠️ 수정된 안전한 스크립트
```python
import frida
import time
import sys
import os
def fixed_memory_analysis():
mail_exe_path = "mail.exe"
# 수정된 JavaScript 코드 (안전한 버전)
js_code = """
console.log("=== MAIL.EXE 메모리 분석 시작 ===");
function safeMemoryAnalysis() {
try {
// 1. 프로세스 기본 정보
console.log("\\n[1] 프로세스 정보:");
console.log("PID: " + Process.id);
console.log("아키텍처: " + Process.arch);
console.log("플랫폼: " + Process.platform);
// 2. 모듈 찾기
console.log("\\n[2] 모듈 검색:");
var modules = Process.enumerateModules();
console.log("총 모듈 개수: " + modules.length);
var targetModule = null;
// 첫 10개 모듈 출력
for (var i = 0; i < Math.min(modules.length, 10); i++) {
var mod = modules[i];
console.log("모듈[" + i + "]: " + mod.name + " -> " + mod.base);
if (i === 0) {
targetModule = mod; // 첫 번째 모듈을 타겟으로
}
}
if (!targetModule) {
console.log("ERROR: 사용할 모듈이 없습니다");
return;
}
console.log("\\n[3] 타겟 모듈: " + targetModule.name);
console.log("베이스 주소: " + targetModule.base);
console.log("모듈 크기: " + targetModule.size);
// 3. 주소 계산
var baseAddr = targetModule.base;
var offset = 0x4050cf;
var targetAddr = baseAddr.add(offset);
console.log("\\n[4] 주소 계산:");
console.log("베이스: " + baseAddr);
console.log("오프셋: 0x" + offset.toString(16));
console.log("타겟: " + targetAddr);
// 4. 메모리 접근 테스트 (안전한 방법)
console.log("\\n[5] 메모리 접근 테스트:");
try {
// 한 바이트씩 안전하게 읽기
var firstByte = Memory.readU8(targetAddr);
console.log("첫 번째 바이트: 0x" + firstByte.toString(16));
if (firstByte === 0x68) {
console.log("SUCCESS: PUSH 명령어 발견!");
// PUSH 오퍼랜드 읽기
var operand = Memory.readU32(targetAddr.add(1));
console.log("PUSH 오퍼랜드: 0x" + operand.toString(16));
// 문자열 주소로 변환
var stringAddr = ptr(operand);
console.log("문자열 주소: " + stringAddr);
// 문자열 읽기 시도
try {
var originalString = Memory.readUtf8String(stringAddr);
console.log("원본 문자열: '" + originalString + "'");
// 패치 시도
performPatch(targetAddr, stringAddr, originalString);
} catch (stringError) {
console.log("문자열 읽기 실패: " + stringError.message);
}
} else {
console.log("WARNING: PUSH 명령어가 아닙니다 (0x" + firstByte.toString(16) + ")");
// 주변 바이트들 확인
console.log("주변 바이트들:");
for (var i = 0; i < 8; i++) {
try {
var b = Memory.readU8(targetAddr.add(i));
console.log(" [+" + i + "] 0x" + b.toString(16));
} catch (e) {
console.log(" [+" + i + "] 읽기 실패");
}
}
}
} catch (accessError) {
console.log("메모리 접근 실패: " + accessError.message);
// 대안: 문자열 패턴 검색
searchStringPattern();
}
} catch (mainError) {
console.log("메인 분석 오류: " + mainError.message);
console.log("스택: " + mainError.stack);
}
}
function performPatch(pushAddr, stringAddr, originalString) {
console.log("\\n[6] 패치 수행:");
try {
// 새 문자열 할당
var newString = "test";
var newStringAddr = Memory.alloc(newString.length + 1);
Memory.writeUtf8String(newStringAddr, newString);
console.log("새 문자열 할당: " + newStringAddr);
// 메모리 보호 해제
Memory.protect(pushAddr, 8, 'rwx');
console.log("메모리 보호 해제 완료");
// PUSH 오퍼랜드 변경
Memory.writeU32(pushAddr.add(1), newStringAddr.toInt32());
console.log("PUSH 오퍼랜드 변경 완료");
// 검증
var newOperand = Memory.readU32(pushAddr.add(1));
console.log("새 오퍼랜드: 0x" + newOperand.toString(16));
var verifyString = Memory.readUtf8String(newStringAddr);
console.log("새 문자열 검증: '" + verifyString + "'");
console.log("SUCCESS: 패치 완료!");
} catch (patchError) {
console.log("패치 실패: " + patchError.message);
}
}
function searchStringPattern() {
console.log("\\n[7] 문자열 패턴 검색:");
try {
var targetString = "Not available in proxy mode.";
var ranges = Process.enumerateRanges('r--');
console.log("검색할 메모리 범위: " + ranges.length + "개");
for (var i = 0; i < Math.min(ranges.length, 50); i++) {
try {
var results = Memory.scanSync(ranges[i].base, ranges[i].size, targetString);
if (results.length > 0) {
console.log("문자열 발견! 주소: " + results[0].address);
// 직접 문자열 변경 시도
Memory.protect(results[0].address, targetString.length, 'rwx');
Memory.writeUtf8String(results[0].address, "test");
// 나머지 공간 NULL로 채우기
for (var j = 4; j < targetString.length; j++) {
Memory.writeU8(results[0].address.add(j), 0);
}
console.log("SUCCESS: 문자열 직접 변경 완료!");
return;
}
} catch (scanError) {
// 스캔 오류는 무시하고 계속
}
}
console.log("문자열 패턴을 찾을 수 없습니다");
} catch (searchError) {
console.log("검색 오류: " + searchError.message);
}
}
// 1초 후 실행
setTimeout(function() {
safeMemoryAnalysis();
}, 1000);
"""
try:
print("[*] mail.exe 실행 중...")
# 파일 확인
if not os.path.exists(mail_exe_path):
print(f"[-] {mail_exe_path} 파일이 없습니다.")
return
# 프로세스 스폰
pid = frida.spawn([mail_exe_path])
print(f"[+] 프로세스 생성 (PID: {pid})")
# 세션 연결
session = frida.attach(pid)
print("[+] Frida 연결 완료")
# 스크립트 생성
script = session.create_script(js_code)
# 메시지 처리
def on_message(message, data):
if message['type'] == 'send':
print(f"[JS] {message['payload']}")
elif message['type'] == 'error':
print(f"[ERROR] {message['description']}")
if 'stack' in message:
print(f"[STACK] {message['stack']}")
script.on('message', on_message)
script.load()
# 프로세스 재개
frida.resume(pid)
print("[+] 프로세스 재개됨")
print("\n" + "="*40)
print("분석 로그:")
print("="*40)
# 분석 대기
time.sleep(4)
print("\n분석 완료!")
input("엔터를 눌러 종료...")
except Exception as e:
print(f"[-] 오류: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
fixed_memory_analysis()
```
## 🔧 최소한의 테스트 스크립트
```python
import frida
import time
def minimal_test():
"""최소한의 기능으로 테스트"""
js_code = """
console.log("=== 최소 테스트 시작 ===");
setTimeout(function() {
try {
console.log("PID: " + Process.id);
var modules = Process.enumerateModules();
console.log("모듈 수: " + modules.length);
if (modules.length > 0) {
var main = modules[0];
console.log("메인 모듈: " + main.name);
console.log("베이스: " + main.base);
var target = main.base.add(0x4050cf);
console.log("타겟: " + target);
var byte = Memory.readU8(target);
console.log("바이트: 0x" + byte.toString(16));
if (byte === 0x68) {
console.log("PUSH 발견!");
var addr = Memory.readU32(target.add(1));
console.log("주소: 0x" + addr.toString(16));
var str = Memory.readUtf8String(ptr(addr));
console.log("문자열: " + str);
} else {
console.log("PUSH 아님");
}
}
} catch (e) {
console.log("오류: " + e.message);
}
}, 500);
"""
try:
pid = frida.spawn(["mail.exe"])
session = frida.attach(pid)
script = session.create_script(js_code)
def on_message(message, data):
print(message['payload'])
script.on('message', on_message)
script.load()
frida.resume(pid)
time.sleep(2)
except Exception as e:
print(f"오류: {e}")
if __name__ == "__main__":
minimal_test()
```
## ⚠️ 문제 해결 팁
### 1. JavaScript 문법 확인
- `padStart()` 같은 ES6 함수 사용 금지
- 문자열 연결은 `+` 연산자만 사용
- `try-catch` 블록으로 모든 메모리 접근 보호
### 2. Frida 버전 확인
```bash
frida --version
pip install --upgrade frida-tools
```
### 3. 권한 문제
```bash
# 관리자 권한으로 실행
# 또는 UAC 설정 확인
```
최소 테스트 스크립트부터 실행해서 단계별로 문제를 확인해보세요. 어떤 오류 메시지가 나오는지 알려주시면 더 구체적으로 도와드리겠습니다.카테고리 없음