본문 바로가기

카테고리 없음

ㄷㄷ

**결론**: "타입에러 낫 어 펑션" 오류는 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 설정 확인
```

최소 테스트 스크립트부터 실행해서 단계별로 문제를 확인해보세요. 어떤 오류 메시지가 나오는지 알려주시면 더 구체적으로 도와드리겠습니다.