#include "header.h"
/*operand_type : 넘겨지는 값에 따라 rva 값을 유동적으로 처리하기 위함*/
ULONGLONG convert_rva_to_raw(const u_char* binary_buf, void* rva_value, operand operand_type)
{
IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)binary_buf;
switch (operand_type)
{
case OPERAND_DWORD:
{
DWORD raw;
IMAGE_NT_HEADERS32* rtr_inh32 = (IMAGE_NT_HEADERS32*)(binary_buf + idh->e_lfanew);
IMAGE_SECTION_HEADER* rtr_ish = (IMAGE_SECTION_HEADER*)(binary_buf + idh->e_lfanew + sizeof(rtr_inh32->Signature) + sizeof(rtr_inh32->FileHeader) + rtr_inh32->FileHeader.SizeOfOptionalHeader);
for (int i = 0; i < rtr_inh32->FileHeader.NumberOfSections; i++, rtr_ish++)
{
// rva 값이 현재 section의 max치 메모리 값 이상이거나 min치 메모리 값보다 작으면 진행하지 않고 for문으로 되돌아간다.
if (*(DWORD*)rva_value >= rtr_ish->VirtualAddress && *(DWORD*)rva_value < (rtr_ish->VirtualAddress + rtr_ish->Misc.VirtualSize))
{
raw = *(DWORD*)rva_value - rtr_ish->VirtualAddress + rtr_ish->PointerToRawData;
return raw;
}
}
break;
}
case OPERAND_ULONGLONG:
{
ULONGLONG raw;
IMAGE_NT_HEADERS64* rtr_inh64 = (IMAGE_NT_HEADERS64*)(binary_buf + idh->e_lfanew);
IMAGE_SECTION_HEADER* rtr_ish = (IMAGE_SECTION_HEADER*)(binary_buf + idh->e_lfanew + sizeof(rtr_inh64->Signature) + sizeof(rtr_inh64->FileHeader) + rtr_inh64->FileHeader.SizeOfOptionalHeader);
for (int i = 0; i < rtr_inh64->FileHeader.NumberOfSections; i++, rtr_ish++)
{
// rva 값이 현재 section의 max치 메모리 값 이상이거나 min치 메모리 값보다 작으면 진행하지 않고 for문으로 되돌아간다.
if (*(ULONGLONG*)rva_value >= rtr_ish->VirtualAddress && *(ULONGLONG*)rva_value < (rtr_ish->VirtualAddress + rtr_ish->Misc.VirtualSize))
{
raw = *(ULONGLONG*)rva_value - rtr_ish->VirtualAddress + rtr_ish->PointerToRawData;
return raw;
}
}
break;
}
}
return (ULONGLONG) - 1;
}
RVA 값이 해당하는 섹션의 구해 해당 섹션의 정보를 이용해 RAW 값을 구해준다.
매개변수
ULONGLONG convert_rva_to_raw(const u_char* binary_buf, void* rva_value, operand operand_type)
ULONGLONG 반환형 : 기본적으로 ULONGLONG형으로 반환하고 호출하는 쪽에서 필요에 의해 반환형을 명시적으로 바꾸도록 했다.
binary_buf : 함수 내에서 섹션의 개수만큼만 for문을 돌면서 검사하기 때문에 file header 구조체 정보가 필요하고, rva 값을 raw 값으로 변환함에 있어 section header의 정보가 필요하기 때문에 buf 자체를 받는다.
rva_value : rva_value의 값이 DWORD형인지 ULONGLONG 형인지 명시적으로 하기 힘드므로 void* 형으로 받고, 함수 내에서 명시적으로 자료형을 표기해 계산한다.
typedef enum
{
OPERAND_DWORD,
OPERAND_ULONGLONG,
OPERAND_NT32,
OPERAND_NT64,
OPERAND_NT32_DATADIRECTORY,
OPERAND_NT64_DATADIRECTORY
} operand;
operand_type : 위의 익명 enum 구조체로 정의된 값 중 dword인지 ulonglong인지에 따라 그에 맞는 파싱 작업을 해 출력하도록 하기 위함이다.
rva 값을 raw 값으로 변환하는 알고리즘
1. RVA가 속해 있는 섹션을 찾는다.
2. 간단한 비례식을 사용해 파일 offset(RAW)를 계산한다.
IMAGE_SECTION_HEADER 구조체에 의하면 비례식은 아래와 같다.
RAW - PointerToRawData = RVA - VirtualAddress
RAW = RVA - VirtualAddress + PointerToRawData
즉, 총 5개의 섹션이 있다고 했을 때 for문을 이용해 RVA 값이 각 섹션의 VirtualAddress 값보다는 크고
VirtualAddress + VirtualSize 값보다는 작을 때를 구하고, 어떤 섹션 범위에 속하는지 구해졌다면, 해당 섹션의 VirtualAddress 값과 PointerToRawData을 이용해 raw 값을 계산한다.
RVA 값에서 구해진 섹션의 VirtualAddress 값을 빼고, 이어서 구해진 섹션의 PointerToRawData 값을 더하면 RAW 값이 나온다.
'toy project > Reversing' 카테고리의 다른 글
[Toy project] PE Viewer 툴 만들기(8) print_ied.c (0) | 2023.07.27 |
---|---|
[Toy Project] PE Viewer 툴 만들기(7) print_iid.c (0) | 2023.07.27 |
[Toy Project] PE Viewer 툴 만들기(5) print_section_header.c (0) | 2023.07.26 |
[Toy Project] PE Viewer 툴 만들기(4) print_inh_ioh_datadirectory.c (0) | 2023.07.26 |
[Toy Project] PE Viewer 툴 만들기(3) print_nt_header.c (0) | 2023.07.26 |