반응형

바이너리 파일을 읽고 유니코드 문자열을 찾아 수정해 보자.

 

Procmon64.exe
2.04MB

이 파일의 내용을 읽고 수정해 보자.

 

 

Procmon64.exe 파일의 0xF9560 위치에 'ProcM' 이라는 유니코드(UTF-16) 문자열이 있다.

 

import binascii

with open("Procmon64.exe", "rb") as f:
	f.seek(0xf9560) # 파일 포인터 이동
	data = f.read(10)
	print(f"Bytes: {data}")
	print(f"Hex: {binascii.b2a_hex(data).decode().upper()}")
	print(f"Unicode: {binascii.unhexlify(binascii.b2a_hex(data)).decode(encoding='utf-16', errors='ignore')}")
	print("File Pointer Position: " + hex(f.tell()).upper())  # 현재 파일 포인터 위치 출력

 

0xF9560위치에서 10바이트를 읽고 출력해 보자.

 

'ProcM' 문자열이 읽혀진다.

 

 

import binascii

with open("Procmon64.exe", "r+b") as f:
    f.seek(0xf9560) # 파일 포인터 이동
    pattern = "QrocM".encode(encoding="utf-16le").hex()
    f.write(bytes.fromhex(pattern))	

    f.seek(-10, 1)  # 현재 위치(1)에서 10바이트 앞으로 이동
    data = f.read(10)
    print(f"Bytes: {data}")
    print(f"Hex: {binascii.b2a_hex(data).decode().upper()}")
    print(f"Unicode: {binascii.unhexlify(binascii.b2a_hex(data)).decode(encoding='utf-16', errors='ignore')}")

 

'ProcM'을 'QrocM'으로 바꿔보자.

 

문자열이 'QrocM'으로 바뀌었다.

 

파일을 직접 확인해 보자.

 

 

import binascii

file_name = "Procmon64.exe"
pattern = "ProcM"
byte_sequence = pattern.encode(encoding="utf-16le")

def find_all_bytes(file_name, byte_sequence):
    with open(file_name, 'rb') as f:
        file_content = f.read()  # 파일 전체를 바이트열로 읽어옵니다.

    occurrences = []
    start_index = 0
    while True:
        try:
            # find() 메서드는 일치하는 위치의 인덱스를 반환합니다.
            index = file_content.find(byte_sequence, start_index)
            if index == -1:
                break  # 더 이상 일치하는 패턴이 없으면 루프를 종료합니다.
            occurrences.append(hex(index).upper())
            start_index = index + len(byte_sequence)  # 다음 검색 시작 위치를 갱신합니다.
        except ValueError:
            break

    return occurrences

positions = find_all_bytes(file_name, byte_sequence)

print(f"문자열 {pattern}({byte_sequence.hex().upper()})이(가) 발견된 위치:")
for idx, pos in enumerate(positions):
    print(f"{idx+1}. 오프셋 [{pos}]에서 발견됨.")

 

파일 전체에서 'ProcM' 문자열을 찾아보자.

 

5개의 'ProcM' 문자열이 발견되었다.

 

직접 확인해 보자. 5개의 같은 결과가 나온다.

 

 

import re

text = "The rain in Spain stays mainly in the plain.".encode(encoding="utf-16le")
print(f"UTF-16 Text: {text}")

matches = re.findall("ain".encode(encoding="utf-16le"), text)  # 대소문자 구분
print(matches)

matches = re.findall("Ain".encode(encoding="utf-16le"), text, re.IGNORECASE)  # 대소문자 무시
print(matches)

 

'PROCM', 'procm', 'Procm' 등 대소문자 구분없이 모든 문자열을 찾기 위해 파이썬 정규식 표현을 살펴보자.

 

코드 마지막에서 'Ain' 문자열을 대소문자 구분 없이 모두 찾았다.

 

import re

text = "The rain in Spain stays mainly in the plain.".encode(encoding="utf-16le")
pattern = "Ain".encode(encoding="utf-16le")
print(f"UTF-16 Text: {text}")
print(f"UTF-16 Pattern: {pattern}")

for idx, match in enumerate(re.finditer(pattern, text, re.IGNORECASE)):
    print(f"{idx+1}. {match.group()} found at byte offset: {match.start()}")

 

이번엔 finditer()로 문자열의 위치까지 정확히 찾아보자.

 

찾은 문자열의 위치가 표시된다. (문자 하나는 2바이트)

 

 

import binascii
import re

file_name = "Procmon64.exe"
pattern = "ProcM"
byte_sequence = pattern.encode(encoding="utf-16le")

with open(file_name, 'rb') as f:
    file_content = f.read()
    print(f"Searching for pattern: {pattern}")

    # Find all occurrences of the byte sequence in the file content
    for idx, match in enumerate(re.finditer(byte_sequence, file_content, re.IGNORECASE)):
        print(f"{idx+1:2}. {binascii.unhexlify(binascii.b2a_hex(match.group())).decode(encoding='utf-16', errors='ignore')} \
        found at byte offset: {hex(match.start()).upper()}")

 

위 결과를 바탕으로 'ProcM' 문자열을 대소문자 구분 없이 찾아보자.

 

'ProcM' 문자열이 대소문자 구분없이 모두 찾아졌다.

 

직접 확인해 봐도 40개의 결과가 표시된다.

 

import binascii
import re

def replace_pattern_in_file(file_name, pattern, replacement):
    byte_sequence = pattern.encode(encoding="utf-16le")
    with open(file_name, 'r+b') as f:
        file_content = f.read()
        print(f"Searching for pattern: {pattern}")

        # Find all occurrences of the byte sequence in the file content
        # Case-sensitive search
        for idx, match in enumerate(re.finditer(byte_sequence, file_content)):
            print(f"{idx+1:2}. {binascii.unhexlify(binascii.b2a_hex(match.group())).decode(encoding='utf-16', errors='ignore')} found at byte offset: {hex(match.start()).upper()}")
            
            f.seek(match.start())
            f.write(replacement.encode(encoding="utf-16le"))
            print(f"   => Replaced with: {replacement} at byte offset: {hex(match.start()).upper()}")

file_name = "Procmon64.exe"
pattern = "ProcM"

replace_pattern_in_file(file_name, pattern, "Q")

 

파일에서 대소문자를 구분해 문자열을 모두 찾아 바꾸는 함수를 작성했다.

함수에 파일 이름, 찾을 문자열, 바꿀 문자열을 인자로 주고 실행한다.

 

모든 'ProcM'이 'QrocM'으로 바뀌었다.

 

반응형
Posted by J-sean
:
반응형

기드라에서 인식하지 못하는 유니코드 문자열을 인식시켜 보자.

 

Music_Player.zip
9.52MB

 

x64dbg로 분석 시 제대로 인식되는 유니코드 문자열이 있다.

 

이 부분을 Ghidra로 분석해 보면 문자열이 인식되지 않는다.

 

문자열 코드로 이동한다. 함수로 인식되어 있다.

 

문자열 부분을 모두 선택하고 우클릭 - Clear - Clear Code Bytes를 클릭한다.

 

 

함수로 인식됐던 내용이 삭제되면 다시 우클릭 - Data - TerminatedUnicode 클릭

 

유니코드 문자열로 제대로 인식됐다.

 

디스어셈블리에서도 제대로 인식된다.

 

사실 x64Dbg에서도 문자열 코드의 디스어셈블리 내용을 보면 문자열로 인식되지는 않는다.

 

※ 참고

0x00402bac의 문자열 부분 Hex Code 는 아래와 같다.

310084BD2000F8BBACB9E3B430AECCB9200000ACA5B269D5C8B2E4B22E00

 

유니코드는 한 문자가 2바이트로 구성되며 Little Endian 방식이므로 뒤집어서 해석해야 한다.

예를 들어 '분'이라는 글자는 유니코드로 bd84이지만 Hex Code에는 84bd로 저장되어 있다.

 

그러므로 '1분 미리듣기만 가능합니다.'의 유니코드는 아래와 같다.

0x0031 0xbd84 0x0020 0xbbf8 0xb9ac 0xb4e3 0xae30 0xb9cc 0x0020 0xac00 0xb2a5 0xd569 0xb2c8 0xb2e4 0x002e

 

이 링크에서 위 유니코드를 Input에 입력하면 변환된 문자열을 확인 할 수 있다.

 

 

 

반응형
Posted by J-sean
:
반응형

Below code shows how to use cv::String class.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <opencv2/opencv.hpp>
 
using namespace std;
using namespace cv;
 
int main(int argc, char** argv)
{
    const char* str = "Open Source Computer Vision";
    String str1("Hello World");
    String str2(str, str+11);
    String str3 = "Software Engineer";
 
    cout << "str1: " << str1 << endl << "str2: " << str2 << endl
        << "str3: " << str3 << endl << endl;
 
    cout << "*str1.begin(): " << *str1.begin() << endl;
    cout << "str1[1]: " << str1[1<< endl;
    cout << "*(str1.end()-1): " << *(str1.end()-1<< endl << endl;
 
    cout << "str2.size(): " << str2.size() << endl;
    cout << "str2.length(): " << str2.length() << endl;
    cout << "str2.empty(): " << str2.empty() << endl;
    cout << "str3.find(\"ng\"): " << str3.find("ng"<< endl << endl;
 
    cout << "format(\"%s %d\", str3.c_str(), 100): " << format("%s %d", str3.c_str(), 100<< endl;
    cout << "str3.toLowerCase(): " << str3.toLowerCase() << endl;
    cout << "str3.substr(2, 4): " << str3.substr(24<< endl << endl;
 
    str1.swap(str3);
    cout << "str1.swap(str3)" << endl;
    cout << "- str1: " << str1 << endl << "- str3: " << str3 << endl;
    str1.clear();
    cout << "str1.clear()" << endl;
    cout << "- str1: " << endl;
 
    return 0;
}
cs






반응형
Posted by J-sean
: