프로젝트

[프로젝트]언후킹 과정 상세 분석

poiri3r 2025. 10. 27. 16:37

오늘은 저번에 살펴봤던 conti ransomeware를 한층 더 깊게 살펴보도록 하겠습니다.

conti의 main에서 DisableHooks()를 실행하면서 언후킹이 시작됩니다.

라이브러리에서 dll들을 로드한 뒤 OBFA 매크로를 사용해서 난독화합니다.

그리고 성공한 라이브러리에 대해 removeHook 함수를 호출하는데 removeHook은 locker폴더 내의 antihook 폴더에 들어있습니다.

깃허브 소스코드엔 removeHook 함수가 구현되어 있지 않아서 보고서에 나온 내용들을 확인했는데, DLL재매핑방법을 통해 모듈 덮어쓰기를 통한 언후킹을 사용합니다. 다음과 같은 순서로 진행됩니다.

  1. 원본 파일 경로 획득
  2. 깨끗한 사본 생성
  3. 훅 탐지(바이트 비교)
  4. 메모리 권한 변경
  5. 원본 코드로 덮어쓰기
  6. 권한 복원

의 형태로 진행이 됩니다.

conti 소스코드에 removeHook이 남아있지가 않아서 다른 소스코드들을 찾아보았습니다.

 

\https://github.com/NtRaiseHardError/AntiHook/tree/master

 

GitHub - NtRaiseHardError/AntiHook: PoC designed to evade userland-hooking anti-virus.

PoC designed to evade userland-hooking anti-virus. - NtRaiseHardError/AntiHook

github.com

 

깃허브에 공부하기 좋아보이는 안티훅 코드가 있어서 가져왔습니다.

해당 부분은 초기화 및 프로세스의 모든 DLL모듈 목록을 가져와서 hMopdules라는 배열에 저장합니다.

 

첫번째 단개는 훅 스캐닝입니다

훅 스캐너 실행하는 부분입니다.

CheckModuleForHooks는 isHooked함수로 훅이 되었는지 안되었는지 진단하는 역할을 합니다.

훅의 존재 여부를 확인하는 함수는 isHooked함수이고 한번 살펴보겠습니다.

lpAddress의 바이트 단위로 검사해서 인라인 후킹시 심어두는 jmp를 탐지합니다.

jmp는 다양한 패턴이 있고 다양한 우회방법이 있기 때문에 최대한 많은 점프패턴을 담기위해 여러가지 버전을 넣어뒀습니다.,

conti ransomeware에서는 e9와 0xff 0x25(NOP+JMP)만 탐지하는 것에 비해 엄청 많은 점프 패턴을 탐지하고 있습니다.

 

hModules에 검사할 모듈의 핸들(메모리주소)를 넘겨주고,.

훅이 발견될 경우 상세 정보를 저장할 배열을 전달합니다.

이 함수의 결과는 cbNeeded 값을 0에서 다른값으로 바꿔줍니다.

 

cbNeeded == 0 일때는 그냥 no Hooks detected만 출력합니다.

아닐때는 cbNeeded 개수만큼 PrintHookFuncInfo를 호출해 각 후킹의 상세 정보를 출력합니다.

훅의 상세정보를 출력하는 PrintHookFunInfo

mod[i] -> dwNumHooks = cbNeeded //모듈에서 찾아낸 훅의 총 개수 저장
strncpy(mods[i]->szModuleName, szModuleName, sizeof(mods[i]->szModuleName) - 1);
//모듈의 이름을 mods 구조체에 복사
dwNumHooks += cbNeeded; //dwNumHooks += cbNeeded; //발견된 훅의 개수를 전체 훅 개수에 더함

참고로 모듈은 MODULE_HOOK_INFO라는 구조체를 가리키는 포인터들의 배열입니다.

MODULE_HOOK_INFO는 각각 모듈의 핸들, 전체 파일 경로, 발견된 훅의 총 개수, 개별 훅들의 정보를 저장합니다.

 

두 번째 파트는 훅 제거 실행단계입니다.

한번 더 모듈들을 순회하면서 dwNumHooks값을 확인한 뒤 훅이 1개이상 발견된 모듈만 UnHookModule입니다.

실제로 언후킹을 실행하는 함수는 UnHookModule이고 /AntiHook/AntiHook/Antihook.c에 저장되어 있습니다.

 

UnHookModule에 대해 살펴보겠습니다.

함수가 좀 길어서 핵심적인 부분들만 살펴보겠습니다.

훅이 걸린 함수의 원본 파일 경로를 획득해서 저장합니다.

흐름을 간단하게 보면

1. 훅이 걸린 모듈의 원본 경로 획득

2.디크스에서 원본 DLL 파일을 읽기 전용으로 엶(CreateFile)

3.깨끗한 원본 파일을 lpMapping이라는 새로운 메모리 주소에 로드 

 

언후킹 함수입니다.

여기서 ReplaceExecSection이 핵심 함수인데 후킹된 함수의 코드영역(.text 섹션)을 새로 로드한 모듈(lpMapping)의 코드 영역에 통째로 덮어쓰는 방식입니다.

최대한 요약해서 적어놨습니다./

이상으로 언후킹 분석에 대해 포스팅을 마치겠습니다.

궁금한 점은 댓글이나 쪽지 보내주시면 답변드리겠습니다.

읽어주셔서 감사합니다.