
Windows용 패커 작성 방법에 대한 튜토리얼!

부담스러워 보이나요? 이 readme를 요약한 프레젠테이션 버전을 시도해 보세요. YouTube 동영상이 곧 공개됩니다!
패커는 자신의 주소 공간(때로는 다른 프로세스의 주소 공간) 내에서 다른 프로그램을 압축 해제하고 실행하는 프로그램입니다. 디버거나 가상 샌드박스와 같은 분석 환경을 공격하는 벡터로 알려져 있기도 합니다. 주로 다음과 같은 몇 가지 용도로 사용됩니다:
기본적으로 패커는 몇 가지 기본 단계만 수행합니다:
마찬가지로 간단하게, 패커는 몇 가지 구성 요소로만 이루어져 있습니다:
패커를 빌드하는 것은 까다로울 수 있습니다. 스텁을 빌드하여 패커 실행 파일에 어떻게든 포함시켜야 하기 때문입니다. Windows의 경우 단순 컴파일을 넘어 Visual Studio의 빌드 시스템을 배우는 것은 힘든 작업이 될 수 있습니다. 다행히 CMake는 Visual Studio를 지원하는 간단하고 크로스 플랫폼인 빌드 시스템을 제공하며, 커스터마이징도 매우 용이합니다!
이 튜토리얼은 다음을 가르치는 것을 목표로 합니다:
이미 C++와 CMake에 익숙하다면 패킹 섹션으로 바로 건너뛰어도 좋습니다. 그렇지 않다면 계속 읽어 보세요!
먼저, 이 빌드 시스템이 제대로 작동하여 올바르게 패킹된 실행 파일을 생성한다는 것을 어떻게든 증명해 봅시다. CMake와 Visual Studio를 설치한 후, 원하는 터미널로 이 저장소의 루트 디렉터리로 이동하여 다음을 실행하세요:``` $ mkdir build $ cd build $ cmake ../
이렇게 하면 packer 튜토리얼 코드를 빌드하는 데 필요한 프로젝트 파일이 생성됩니다. 그런 다음 실행하세요:```
$ cmake --build ./ --config Release
이렇게 하면 Release 모드로 packer 프로젝트가 빌드됩니다. 그런 다음, 다음 테스트를 실행할 수 있습니다:```
$ ctest -C Release ./
If all goes well, test\_pack and test_unpack should succeed. If you want to see the results of the packing yourself, you should see this:
모든 것이 잘 진행된다면, test\_pack과 test_unpack은 성공해야 합니다. 패킹 결과를 직접 확인하고 싶다면, 다음과 같은 결과를 보게 될 것입니다:```
$ ./packed.exe
I'm just a little guy!
패커를 구성하는 모든 요소에 대해 이야기해 봅시다.
패커의 주요 구성 요소가 무엇인지는 알았지만, 개발 주기 중에 패커를 바로 테스트하려면 어떻게 해야 할까요? 바이너리의 패킹 및 언패킹 과정을 제대로 테스트하려면 전체 프로젝트에 세 번째 바이너리를 추가해야 합니다. 즉, 전체적으로 다음 세 개의 프로젝트가 필요합니다.
또한 바이너리가 스텁 실행 파일로 압축되도록 하려면 압축 라이브러리도 필요합니다. zlib이 여기에 잘 맞을 것입니다.
시작 단계에서 우리 프로젝트 구조는 다음과 같아야 합니다.``` packer/ +---+ CMakeLists.txt + dummy/ | | | +---+ CMakeLists.txt | + src/ | | | +---+ main.cpp | + stub/ | | | +---+ CMakeLists.txt | + src/ | | | +---+ main.cpp | + src/ | | | +---+ main.cpp | + zlib-1.2.13/ | +---+ CMakeLists.txt + ...
각 폴더의 main.cpp는 지금은 단순히 다음과 같이 보일 수 있습니다:```cpp
#include <iostream>
int main(int argc, char *argv[]) {
std::cout << "I'm just a little guy!" << std::endl;
return 0;
}
Already, we should establish that we have a simple dependency chain to deal with, which CMake will nicely resolve for us with some instrumentation:
CMake 계측을 위해 루트 프로젝트, 즉 packer부터 시작하겠습니다.
CMake는 일반적으로 처리할 최소 버전을 요구합니다. 오랫동안 존재해 왔고 이전 버전의 장기 사용을 지원하기 때문입니다. 그 후에는 packer 프로젝트를 C++ 프로젝트로 선언할 수 있습니다.```cmake
cmake_minimum_required(VERSION 3.24)
project(packer CXX)
또한 패커를 "MultiThreadedDLL"(즉, /MD) 대신 "MultiThreaded"(즉, /MT)로 선언하여 런타임 DLL 종속성에 대해 걱정할 필요가 없도록 하고 싶습니다.```cmake
# this line will mark our packer as MultiThreaded, instead of MultiThreadedDLL
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
변수 설정 문에서 꺾쇠 괄호 안의 문은 generator expression이라고 하며, 필요할 때 구성 시 데이터를 확인하는 데 도움이 됩니다. 이 파일 전체에서 자주 보게 될 것입니다. 이 generator expression은 구성이 Debug임을 감지하면 Debug 문자열을 내보내고, 그렇지 않으면 아무것도 내보내지 않습니다. 따라서 컴파일 프로필로 Debug를 선택하면 MultiThreadedDebug 런타임 라이브러리가 제공되고, Release와 같은 디버그가 아닌 컴파일 프로필을 선택하면 MultiThreaded가 제공됩니다. 무슨 일이 일어나고 있는지 잘 이해하려면 조건부 generator expression을 참조하세요. CMAKE_MSVC_RUNTIME_LIBRARY 변수에 대한 자세한 내용은 CMake 문서를 참조하세요.
CMake를 사용하면 Visual Studio에서 UI로 프로젝트를 만들 때 자동으로 하는 것처럼 소스 코드를 계층 구조로 구성할 수 있으며, 폴더에서 일치하는 파일 이름을 재귀적으로 검색할 수도 있습니다. 우리 구성 파일에서는 헤더(.hpp), 코드(.cpp), 리소스 스크립트(.rc)에 대해 전역 재귀를 설정했습니다. 이 예제에서는 실제로 main.cpp만 필요하지만, 더 큰 프로젝트에서는 알아 두면 유용합니다.```cmake
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/src/.cpp) file(GLOB_RECURSE HDR_FILES ${PROJECT_SOURCE_DIR}/src/.hpp) file(GLOB_RECURSE RC_FILES ${PROJECT_SOURCE_DIR}/src/*.rc)