오늘은 진행중인 프로젝트의 일환으로 Conti-Ransomware에 대한 소스코드를 분석해보겠습니다.
Conti 랜섬웨어는 러시아계 조직과 연계된 랜섬웨어 서비스 계열 악성코드입니다.
Conti는 22년 2월 소스코드가 유출되었었는데, 이 소스코드를 변형된 랜섬웨어를 사용한 건라라는 조직이 한국의 SGI서울보증을 공격하기도 했었습니다.
https://github.com/gharty03/Conti-Ransomware
GitHub - gharty03/Conti-Ransomware: Full source of the Conti Ransomware Including the missing Locker files from the original lea
Full source of the Conti Ransomware Including the missing Locker files from the original leak. I have fixed some of the errors intentionally introduced by the leaker to prevent the locker from bein...
github.com
해당 깃허브에 나와있는 코드와 다른 연구 결과들을 검색해서 분석을 했고, 참조된 사이트들은 가장 아래에 링크 달아두겠습니다.
Conti는 Visual studio 2015에서 C++을 사용하여 개발되었습니다.

콘티의 구조입니다.

깃허브에 올라온 파일들에 해당하는 부분을 찾을 수 있었습니다.
콘티는 총 8단계로 진행됩니다.
- API 해싱
- API 언후킹
- 뮤텍스 생성
- 랜섬 노트 생성
- 시스템의 스냅샷/백업 삭제
- 보안 프로세스 강제 종료
- 멀티쓰레드 생성
- 파일 암호화
용어를 살짝 정리만해보고 가자면
API해싱은 CreateFileW와 같은 API 이름을 코드에 그대로 두지 않고 해시값(숫자)로 바꿔서 가지고 있다가 실행중에 모듈의 export 테이블을 훑어 이름을 해시->해시값 비교로 API 주소를 찾는 기법입니다.
이러한 기법은 탐지를 회피하고 IAT 없이 동적 로딩이 가능합니다.
API언후킹은 백신과 같은 보안 제품이나 모니터링 코드가 걸어둔 API 후킹을 런타임에 우회함으로 탐지를 회피하는 목적입니다.
뮤텍스생성은 파일의 중복 암호화를 방지하기 위한것으로, 이미 랜섬웨어가 실행중일 경우 새 프로세스가 바로 종료하도록 합니다.
Conti의 메인(WinMain)부분을 확인해보겠습니다.
1. API 해싱

Winmain은 api.cpp파일에 저장된 InitializeApiModule함수를 호출하면서 시작합니다.
api.cpp에 저장된 해당 함수의 소스코드는 다음과 같습니다.

해당 코드에서는 kernel32.dll을 로드하고 GetApiAddr함수를 이용하여 kernel32의 익스포트 테이블을 스캔해서 해시값에 해당하는 함수의 주소를 찾아 dwLoadLibraryA에 써넣습니다.
=> 해당 부분이 API 해싱으로 LoadLibraryA의 실제 주소를 얻는 단계입니다.
안에 GetApiAddr함수도 살펴보겠습니다.

마찬가지로 api.cpp에 선언이 되어있습니다.
해당 코드를 요약해보면 런타임에 확인된 API 이름을 Murmur2A알고리즘을 활용하여 해싱하여 숨깁니다.
(Murmur2A는 비암호학적 해시함수인 MurmurHash2의 변형으로 오픈소스로 제공됩니다)
if (MurmurHash2A(ProcName, StrLen(ProcName), HASHING_SEED) == ProcNameHash)
{
Ordinal = *OrdinalTable;
Found = TRUE;
break;
}
해당 코드를 통해MurmurHash2 알고리즘으로 해싱함을 알 수 있습니다.
2.API 언후킹

WinMain함수에서의 두번째 호출입니다.
api.cpp에 정의되어 있습니다.

OBFA()는 문자열 난독화 매크로입니다. 여기서 난독화해서 라이브러리들을 로드하고 ,

해당 함수들에 대해 removeHooks를 적용합니다.
removeHooks는 locker / antihook / 경로에 있다는데 깃허브 소스코드에 antihooks.cpp이 없어서 참고자료에 있는 내용을 가져오겠습니다.
antihooks.h에서 선언되는 부분은 있는데 코드부분이 없네요 ㅜ


라고 나와있는데 이런 0xff 0xe9 0x25명령어들을 확인하는 이유는 인라인 후킹을 탐지하기 위해서입니다.
인라인후킹에 대해서는 전에 포스팅한적이 있어서 링크를 남기겠습니다.
https://poiri3r.tistory.com/21
[Reversing] Hooking - 5 (Inline Hooking ①)
안녕하세요. 오늘 포스팅은 후킹의 마지막 파트인 인라인 후킹에 대해 포스팅을 해보겠습니다.여태까지 IAT후킹과 Frida를 활용한 WinAPI후킹 및 동적 후킹을 해봤습니다.저번 IAT후킹 포스팅할 때
poiri3r.tistory.com
이렇게 후크를 탐지하면

해당사진에서 나오는 코드들이 후킹 탐지에서 탐지된 바이트를 원래 라이브러리 바이트로 변경합니다(메모리 패칭)
(CopyMemory 함수에서 funcAddr에서 10바이트를 가져와 funchHooked위치로 복사)
3. 뮤텍스 생성

다음으로 랜섬웨어는 "kjsidugidf99439"라는 하드코딩된 이름을 가진 뮤텍스를 생성합니다. 마찬가지로 OBFA매크로를 통해 난독화됩니다.
pCreateMutexA는 실제 CreateMutexA API 함수의 포인터를 동적으로 불러온 형태입니다.
각각의 인자는 " kjsidugidf99439"라는 이름을 가진 뮤텍스를 생성하면서 즉시 잠급니다.
또 이미 같은 이름의 뮤텍스가 있다면 EXIT_FAILURE로 즉시 종료합니다.
(랜섬노트 생성 부분은 생략하겠습니다)
4.섀도 복사본 삭제

다음은 DeleteShadowCopies를 호출합니다.
해당 함수는 locker.cpp파일안에 코드가 들어있습니다.

해당 함수는 WMI COM API를 이용해 시스템의 볼륨 섀도 복사본을 찾아 삭제하는 루틴입니다.

wsprintfW(CmdLine, OBFW(L"cmd.exe /c C:\\Windows\\System32\\wbem\\WMIC.exe shadowcopy where \"ID='%s'\" delete"), vtProp.bstrVal);
간단하게 보면 섀도 복사본 ID를 받아온 후 cmd.exe /c ... 명령을 통해 섀도 복사본을 삭제합니다.
해당함수에 해당하는 코드가 꽤 긴데, 해당 작업이 관리자 권한이 필요하기 때문에 WMI 인증을 우회하는 과정이 필요하기 때문입니다.
6.화이트리스트 프로세스 설정

해당 코드는 locker/process_killer.cpp에 들어있습니다.


코드 안에서 explorer.exe를 찾아서 화이트리스트(Pidlist)에 추가합니다.
해당 함수는 process_killer가 실행될 때 윈도우 셸을 종료하지 않으려는 목적입니다.

위의 코드는 process_killer안의 WhitelistNames[]배열입니다. 참고용으로 가져왔습니다.
7. 멀티쓰레드 생성

해당 코드에서 생성할 스레드 수를 결정합니다.
GetNativeSystemInfo를 통해 시스템의 프로세스를 가져오고 생성할 스레드 수는 시스템 프로세서 수의 두배로 결정합니다

해당함수에서 threadpool::Create함수를 사용해서 두개의 스레드를 생성합니다.


threadpool::Start와 threadpool::Create는 각각 locker/threadpool.cpp에 정의되어있습니다.
생성된 각 스레드는 CryptAcquireContextA를 통해 초기화된 암호와 컨텍스트와 각 스레드에 대한 RSA공개키를 갖는 버퍼가 있습니다.

그리고 threadpool.cpp 가장 초반부분에 STATIC으로 퍼블릭키가 저장되어있는 버퍼가 있습니다

8.파일 암호화

chacha20 알고리즘은 locker/chacha20/chacha.c 경로에 저장되어 있습니다.
파일을 암호화할 준비가 되면 locker.cpp파일의 GenKey함수를 호출하여 암호화 키를 생성합니다.

해당 함수에서 CryptgenRandom API를 통해 32바이트의 난수 키와 8바이트 난수 초기 벡터를 생성하고 FileInfo에 저장합니다.
다음으로 32바이트 키를 RSA 공개키를 사용하여 암호화합니다.
locker.cpp에 함수를 보면 암호화 모드가 나눠져있는데

보면 파일의 크기에 따라 암호화 비율이 달라집니다.

그리고

changeFileName이라는 함수가 있어서 getExtension까지 찾아보니

해당 경로에서


파일의 이름을 바꾸는 함수를 찾을 수 있었습니다.
또 메인 암호화 함수는

해당 Encrypt함수이고, 해당 함수에서 키를 생성하고, 파일을 열고, 메타데이터를 기록하고, 실제로 암호화를 진행하는 함수인 EncryptFull(), EncryptHeader(), EncryptPartly()함수를 호출합니다.

암호화 연산은 공통적으로 위의 코드를 통해 ChaCha로 암호화됩니다.
해당 ECRYPT_encrypt_bytes함수는 chacha.c안에 다음과 같이 선언되어 있습니다.

일단 이상으로 포스팅을 마치겠습니다.
본격적으로 소스코드를 분석해본건 처음인데 너무 어렵지만서도 재미있었네요.
분석하는데 참고한 문헌들은 아래 링크로 남겨놓겠습니다.
https://ieeexplore.ieee.org/document/9895237
An Analysis of Conti Ransomware Leaked Source Codes
In recent years, there has been an increase in ransomware attacks worldwide. These attacks aim to lock victims’ machines or encrypt their files for ransom. These kinds of ransomware differ in their implementation and techniques, starting from how they sp
ieeexplore.ieee.org
S. Alzahrani, Y. Xiao and W. Sun, "An Analysis of Conti Ransomware Leaked Source Codes," in IEEE Access, vol. 10, pp. 100178-100193, 2022, doi: 10.1109/ACCESS.2022.3207757.
keywords: {Ransomware;Libraries;Codes;Encryption;Static analysis;Behavioral sciences;Cryptography;Computer security;Computer security;ransomware;static analysis;dynamic analysis;conti ransomware;source codes},
https://seed.kisa.or.kr/kisa/Board/141/detailView.do
이상으로 포스팅을 마치겠습니다.
읽어주셔서 감사합니다
'프로젝트' 카테고리의 다른 글
| [텀프로젝트] 파일 압축&암호화 유틸리티 개발 - 1 ( 파일 선택 구현 ) (1) | 2025.12.11 |
|---|---|
| [프로젝트]언후킹 과정 상세 분석 (0) | 2025.10.27 |
| dropper(js확장자) 분석 (edward-social-lactose-zebra) (1) | 2025.09.18 |
| 정보 보안 침해 사고 (0) | 2025.09.10 |
| QR코드 - 1 ( QR 고정 패턴 ) (4) | 2025.08.09 |