## 핵심 답변
**주소는 맞지만 메모리 읽기에서 JavaScript 함수 호출 문제가 있습니다.** 그리고 명령어는 동일합니다 (CMP dword [ebp-8], eax = CMP dword ptr [EBP + local_c], EAX).
## 확실한 정보
### 명령어 비교 분석
- **Frida**: `cmp dword [ebp - 8], eax`
- **기드라**: `CMP dword ptr [EBP + local_c], EAX`
- **local_c = -8**: 기드라의 local_c는 EBP-8을 의미
- **결론**: **동일한 명령어입니다** ✅
### 수정된 코드 (JavaScript 오류 해결)
```python
import frida
import sys
import os
executable = "mail.exe"
if not os.path.exists(executable):
print(f"❌ {executable} 파일이 없습니다.")
sys.exit(1)
try:
print(f"🚀 {executable} 실행 중...")
device = frida.get_local_device()
pid = device.spawn([executable])
print(f"✅ 프로세스 생성됨 (PID: {pid})")
session = device.attach(pid)
print("✅ 프로세스에 연결됨")
# 베이스 주소 확인
base_address = None
script = session.create_script("""
var mainModule = Process.enumerateModules()[0];
send({
name: mainModule.name,
base: mainModule.base.toString(),
size: mainModule.size
});
""")
def on_message(message, data):
global base_address
if message['type'] == 'send':
info = message['payload']
print(f"📍 모듈명: {info['name']}")
print(f"🎯 실제 베이스 주소: {info['base']}")
base_address = info['base']
script.on('message', on_message)
script.load()
import time
time.sleep(1)
script.unload()
if base_address:
# 올바른 주소 계산
ghidra_address = "0x4066a2"
ghidra_base = "0x400000"
print(f"\n📊 주소 계산:")
print(f" 기드라 주소: {ghidra_address}")
print(f" 기드라 베이스: {ghidra_base}")
print(f" 실제 베이스: {base_address}")
try:
ghidra_addr = int(ghidra_address, 16)
ghidra_base_addr = int(ghidra_base, 16)
real_base = int(base_address, 16)
offset = ghidra_addr - ghidra_base_addr
real_address = real_base + offset
print(f" 오프셋: 0x{offset:x}")
print(f" 실제 주소: 0x{real_address:x}")
# 수정된 검증 및 후킹 코드 (JavaScript 오류 수정)
verification_code = f"""
try {{
var target_addr = ptr("0x{real_address:x}");
console.log("=== 주소 검증 ===");
console.log("타겟 주소: " + target_addr);
// 메모리 읽기 (수정된 코드)
try {{
var instruction = Instruction.parse(target_addr);
console.log("✅ 명령어: " + instruction.mnemonic + " " + instruction.opStr);
// 메모리 바이트 읽기 (올바른 방법)
var buffer = Memory.readByteArray(target_addr, 8);
var bytes = new Uint8Array(buffer);
var hexStr = "";
for (var i = 0; i < Math.min(bytes.length, 4); i++) {{
hexStr += bytes[i].toString(16).padStart(2, '0') + " ";
}}
console.log("메모리 바이트: " + hexStr);
// 첫 바이트 확인 (CMP 명령어 = 0x39)
console.log("첫 바이트: 0x" + bytes[0].toString(16));
if (bytes[0] === 0x39) {{
console.log("✅ CMP 명령어 확인됨! (0x39 45 f8)");
}} else {{
console.log("⚠️ 예상과 다른 바이트: 0x" + bytes[0].toString(16));
}}
}} catch(readErr) {{
console.log("❌ 메모리 읽기 실패:", readErr.message);
}}
// 후킹 설정
console.log("\\n후킹 설정 중...");
var hook = Interceptor.attach(target_addr, {{
onEnter: function(args) {{
console.log("\\n🔥🔥🔥 CMP 명령어 실행됨! 🔥🔥🔥");
console.log("주소: 0x{real_address:x}");
console.log("시간: " + new Date().toLocaleTimeString());
// 레지스터 값 출력
var ebp = this.context.ebp;
var eax = this.context.eax;
console.log("EBP: 0x" + ebp.toString(16));
console.log("EAX: 0x" + eax.toString(16));
try {{
// [EBP-8] 메모리 값 읽기
var ebp_minus_8 = ebp.sub(8);
var memValue = Memory.readU32(ebp_minus_8);
console.log("[EBP-8]: 0x" + memValue.toString(16));
console.log("비교: [EBP-8](0x" + memValue.toString(16) + ") vs EAX(0x" + eax.toString(16) + ")");
}} catch(memErr) {{
console.log("메모리 읽기 오류:", memErr.message);
}}
console.log("--- CMP 명령어 완료 ---\\n");
}}
}});
console.log("✅ 후킹 설정 완료!");
send({{"type": "success", "message": "Hook installed successfully"}});
}} catch(hookErr) {{
console.log("❌ 후킹 실패:", hookErr.message);
send({{"type": "error", "message": hookErr.message}});
}}
"""
hook_script = session.create_script(verification_code)
def on_hook_message(message, data):
if message['type'] == 'send':
payload = message['payload']
if payload.get('type') == 'success':
print(f"✅ {payload['message']}")
elif payload.get('type') == 'error':
print(f"❌ 후킹 오류: {payload['message']}")
hook_script.on('message', on_hook_message)
hook_script.load()
time.sleep(1)
except ValueError as e:
print(f"❌ 주소 계산 오류: {e}")
# 프로세스 재개
device.resume(pid)
print("▶️ 프로그램 실행됨")
print("🎮 해당 CMP 명령어가 포함된 코드 경로를 실행해보세요!")
print(" (함수 호출, 버튼 클릭, 메뉴 선택 등)")
try:
input("종료하려면 Enter...")
except KeyboardInterrupt:
print("\n⏹️ 종료")
except Exception as e:
print(f"❌ 오류: {e}")
finally:
try:
session.detach()
device.kill(pid)
except:
pass
print("🧹 정리 완료")
```
## 주요 수정사항
1. **JavaScript 오류 수정**: `hexdump()` 함수 대신 직접 바이트 처리
2. **메모리 읽기 개선**: `Memory.readByteArray()` 올바른 사용법
3. **레지스터 값 표시**: EBP, EAX 값과 [EBP-8] 메모리 내용 출력
## 명령어 동일성 확인
- **39 45 f8** = CMP dword ptr [EBP-8], EAX
- **Frida 출력과 기드라 출력이 동일함** ✅
이제 JavaScript 오류 없이 정확한 후킹이 가능합니다!카테고리 없음