악성코드와 백신/악성코드 개발일지

[악성코드 개발](3)[Windows API]

황올뱀 2026. 2. 26. 13:57

윈도우 API

앞에 P가 붙으면 그 형식의 포인터를 나타낸다
뒤에 A가 붙으면 ANSI 형식이다
뒤에 W가 붙으면 UNICODE 또는 Wide를 뜻한다.
__IN__, __OUT__ 키워드는 주석용이다.

 

데이터 형식

  • DWORD: 0 ~ $2^{32}-1$까지 나타내는 32비트 값
  • SIZE_T: 객체의 크기를 나타내는데 사용되는 값
    32비트: unsigned int
    64비트: signed int
  • VOID: 데이터 형식이 없음
  • PVOID: 포인터 (= void*)
    32비트: 4바이트 포인터
    64비트: 8바이트 포인터
  • HANDLE: 운영체제가 관리하는 개체를 지정하는 값
    파일, 프로세스, 스레드 등...
  • HMODULE: 모듈에 대한 핸들
    exe, dll 등...
  • LPCSTR / PCSTR (= const char*)
    ANSI문자로 이루어진 null로 끝나는 상수 문자열에 대한 포인터
  • LPSTR / PSTR (= char*)
    읽고 쓰기 가능
  • LPCWSTR / PCWSTR
    UNICODE문자로 이루어진 null로 끝나는 상수 문자열에 대한 포인터
  • wchart: 넓은 문자
  • ULONG_PTR: unsigned int
    주소 값 자체를 숫자로 취급해 마스킹(AND/OR) 등을 할 수 있다

예) CreateFileW를 불러서 파일을 만들어보자

#include <Windows.h>
#include <stdio.h>

int main() {
    HANDLE hFile = INVALID_HANDLE_VALUE; //초기화
    LPCWSTR filepath = L"C:\\Users\\bigsilver\\Desktop\\mal.txt";

    hFile = CreateFileW(filepath, GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hFile == INVALID_HANDLE_VALUE) {
        printf("[-] CreateFileW is failed with error: %d\n", GetLastError());
    }
    else { printf("[+] CreateFileW is success!"); }

    return -1;
}

오류를 가져올 땐 GetLastError()를 통해 가장 마지막에 일어난 오류를 정수로 알 수 있다.
그 밖에도 NTSTATUS의 NT_SUCCESS를 사용해 성공, 실패를 판단할 수도 있다.

 

Portable Excutable 형식

윈도우의 실행파일 형식
예) .exe, .dll, .sys 등의 확장자를 가진다

PE 구조

  • DOS header (IMAGE_DOS_HEADER)
    e_magic: PE파일의 첫번째에는 MZ(0x40, 0x5A)가 항상 들어감
        -> 이걸로 유효한 PE파일인지 확인
    e_lfanew: NT header의 오프셋을 가진 4바이트 값
        항상 0x30 위치에 있음
  • DOS stub
    프로그램이 디스크 작동 모드 or DOS 모드로 로드되면 오류 메세지를 출력
  • NT header (IMAGE_NT_HEADERS)
    • NT 시그니처
      PE (0x50, 0x45) 또는 (0x50450000)
    • file header
      NumberOfSections: PE파일 섹션 수
      Characteristics: dll인지 콘솔 app인지 같은 속성 지정
      SizeOfOptionalHeader: optional header의 크기
    • optional header: 일부 파일에만 없는거지 실제로는 필요함
      magic: 32, 64비트 나타냄
      MajorOperatungSystemVersion: 운영체제 주 버전 번호
      MinorOperatingSystemVersion: 운영체제 부 버전 번호
      SizeOfCode: .text 섹션의 크기
      AddessOfEntryPoint: 파일의 진입점
          일반적으로 main 함수까지의 오프셋
      BaseOfCode: .text 섹션 시작까지의 오프셋
      SizeOfImage: 이미지 파일의 크기
      ImageBase: 로드되고 싶은 주소
          단, ASLR 때문에 ImageBase와 동일하게 할당되는 일은 적다.
          따라서 delta = 실제 주소 - ImageBase 를 구한 후 
          .reloc 섹션에 있는 주소들에 delta를 더해줘 주소를 재배치한다
  • data directory: PE header와 실제 data를 연결
    virtual address: 데이터가 시작되는 상대주소
    size: 데이터 크기
    • export directory(0): 외부에게 내가 제공하는 함수 목록
      -> 악성코드가 API를 변조하거나 유효한 dll인척 위장할 때 이 부분을 조작
    • import directory(1): 외부에서 가져와야 하는 dll과 함수 목록
      -> 악성코드의 기능 파악의 단서
    • resource directory(2): 프로그램이 사용하는 리소스 정보
      -> 악성코드가 추가 실행파일이나 페이로드를 여기에 숨기기도 함
    • 기타등등
  • sections: 데이터 저장소
    .text: 실행 코드
    .data: 읽기 전용 데이터
    .idata: 가져오기 테이블
    .reloc: imagebase + delta 연산을 해야 하는 주소들
    .rsrc: 리소스
반응형