본문 바로가기

카테고리 없음

ㄷㄷ

## 핵심 답변

**주소는 맞지만 메모리 읽기에서 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 오류 없이 정확한 후킹이 가능합니다!