1. 프로세스
윈도우는 리소스를 관리할 목적으로 컨테이너로 프로세스를 사용하고, 프로그램이 상호 간섭하지 않게 분리한다. 윈도우 시스템은 특정 시점에 적어도 20~30개의 프로세스가 CPU, 파일 시스템, 메모리, 하드웨어를 포함한 동일한 자원을 공유하면서 동작한다.
신규 프로세스 생성
악성코드가 신규 프로세스를 생성할 때 가장 흔히 사용하는 함수는 CreateProcess다. 이 함수의 많은 파라미터를 통해 호출자(caller)는 프로세스 생성에 관한 세부적인 제어가 가능하다.
악성코드는 보통 CreateProcess를 이용해 함수 하나만을 호출하는 간단한 원격 쉘을 생성한다. CreateProcess 함수의 파라미터 중 하나는 STARTUPINFO 구조체인데, 이는 프로세스의 표준 입출력과 표준 에러 스트림 핸들을 포함한다. 악성코드는 프로그램이 표준 출력으로 쓸 때 실제 소켓을 써서 공격자가 원격에서 CreateProcess 호출을 제외한 모든 실행이 가능하게 이 값을 소켓으로 설정한다.
mov eax, dword ptr [esp+58h+SocketHandle]
lea edx, [esp+58h+StartUpInfo]
push ecx ; lpProcessInformation
push edx ; lpStartupInfo
mov [esp+60h+StartupInfo.hStdError], eax
mov [esp+60h+StartupInfo.hStdOutput], eax
mov [esp+60h+StartupInfo.hStdInput], eax
eax, dword_403098
push 0 ; lpCurrentDirectory
push 0 ; lpEnvironment
push 0 ; dwCreationFlags
mov dword ptr [esp+6Ch+CommandLine],
eax push 1 ; bInheritHandles
push 0 ; lpThreadAttributes
lea eax, [esp+74h+CommandLine]
push 0 ; lpProcessAttributes
push eax ; lpCommandLine
push 0 ; lpApplicationName
mov [esp+80h+StartupInfo.dwFlags], 101h
call ds:CreationProcessA
코드 첫 줄에서 스택 변수인 SocketHandle을 EAX에 저장한다. 프로세스의 lpStartupInfo 구조체는 신규 프로세스에 이용할 표준 출력, 표준 입력, 표준 에러를 저장한다. dword_403098 접근은 실행할 프로그램의 커맨드라인을 저장하는데, 이는 나중에 파라미터로 스택에 푸시된다.
CreateProcess를 호출하면 모든 입출력을 소켓으로 리다이렉트하기 위해 새로운 프로세스를 생성한다. 외부 호스틀 알아내려면 소켓이 초기화 되는 위치를 알아야 한다. 어떤 프로그램이 동작하는지 알기 위해 어셈블러를 이용해 dword_403098에 저장된 문자열을 알아야 한다.
2. 스레드
프로세스는 실행 컨테이너지만 스레드는 윈도우 운영체제가 실행하는 것이다. 스레드는 다른 스레드 대기 없이 CPU에 의해 실행되는 독립적인 명령어 순서다. 프로세스는 하나 이상의 스레드를 포함하는데, 프로세스 내의 코드 일부를 실행한다. 프로세스 내의 스레드는 메모리 공간을 모두 공유하지만, 각각 개별 프로세서 레지스터와 스택을 보유한다.
스레드 문맥
스레드가 CPU 내부 레지스터 값을 변경할 때 다른 스레드의 영향을 받지 않는다. 운영체제가 스레드를 교체하기 전에 CPU의 모든 값은 스레드 문맥(Thread Context)이라 부르는 구조체에 저장한다. 그런 다음 운영체제는 CPU로 신규 스레드의 스레드 문맥을 로드하고, 신규 스레드를 생성한다.
스레드 생성
CreateThread 함수는 신규 스레드를 생성할 때 사용한다. 이 함수의 호출자는 시작 주소를 명시하는데, 시작 함수(start function)라고 부른다. CreateThread를 호출하는 코드 분석 시 CreateThread를 호출하는 함수 내의 나머지 코드를 분석할 뿐 아니라 시작 함수를 분석할 필요가 있다.
악성코드는 입출력 용도의 신규 스레드 두 개를 생성하는데, 하나는 소켓이나 파이프를 리스닝해 프로세스의 표준 입력을 출력하고 다른 하나는 표준 입력으로 값을 읽어 소켓이나 파이프로 내보낸다.
lea eax, [ebp+ThreadId]
push eax ; lpThreadId
push 0 ; dwCreationFlags
push 0 ; lpParameter
push offset ThreadFunction ; lpStartAddress
push 0 ; dwStackSize lea ecx, [ebp+ThreadAttributes]
push ecx ; lpThreadAttributes call ds:CreateThread
해당 프로세스의 목적을 알려면 ThreadFunction으로 가 봐야 한다.
* 스레드뿐 아니라 마이크로소프트는 파이버(fiber)를 사용한다. 파이버는 스레드와 유사하지만 운영체제가 아닌 스레드에 의해 관리된다. 파이버는 하나의 스레드 문맥을 공유한다.
3. 뮤텍스(뮤턴트)
커널에서 뮤턴트(mutants)라고 부르기도 한다. 뮤텍스는 여러 프로세스와 스레드를 조정하는 전역 객체다. 뮤텍스는 주로 공유 자원 접근 통제에 사용하는 데 악성코드가 자주 이용한다. 예를 들어 두 개의 스레드가 메모리 구조체에 접근해야 하지만 한 번에 하나만이 안전하게 접근할 수 있다면 뮤텍스를 통해 접근을 통제할 수 있다.
하나의 스레드만이 한 번에 하나의 뮤텍스를 소유할 수 있다. 뮤텍스는 주로 하드코딩된 이름으로 되어 있어 악성코드 분석에 중요하며, 좋은 호스트 기반의 표식 이기도 하다.
스레드는 WaitForSingleObject를 호출해 뮤텍스 접근 권한을 얻고 접근을 시도하는 이후 스레드는 기다려야 한다. 스레드의 뮤텍스 사용이 완료되면 ReleaseMutex 함수를 사용한다.
뮤텍스는 CreateMutex 함수로 생성할 수 있다. 하나의 프로세스는 OpenMutex 호출을 통해 다른 프로세스의 뮤텍스 핸들을 얻을 수 있다.
push offset Name ; "HGL345"
push 0 ; bInheritHandle
push 1F001h ; dwDesiredAccess
call ds:__imp__OpenMutexW@12 ; OpenMutexw(x,x,x)
test eax, eax
jz short loc_4010E
push 0 ; int
call ds:__imp__exit
push offset Name ; "HGL345"
push 0 ; bInitialOwner
push 0 ; lpMutexAttributes
call ds:__imp__CreateMutexW@12 ; CreateMutexW (x,x,x)
위 코드는 하드 코딩된 HGL345라는 뮤텍스명을 사용한다. 첫 번째 함수 호출에서 HGL345라는 이름의 뮤텍스명의 존재를 확인한다. 리턴 값이 NULL이면 loc_40101E로 점프해 뮤텍스를 생성하고 프로그램의 또 다른 인스턴스 코드가 종료 코드를 만나기 전까지 실행되게 보증한다.
4. 서비스
윈도우는 백그라운드 어플리케이션으로 실행하는 서비스를 사용해 프로세스나 스레드 없이 실행할 수 있게 하는데, 코드가 스케줄링돼 사용자 입력 없이 윈도우 서비스 관리자가 실행한다.
서비스를 이용하면 악성코드 제작자의 이점에서 많은 이점이 있다. 서비스는 SYSTEM 권한이나 다른 권한 계정으로 실행된다. 이는 서비스를 설치하려면 관리자 권한이 필요하기 때문에 취약점이 아니지만, SYSTEM 계정은 administrator나 사용자 계정보다 상위 권한이므로 악성코드 제작자에게 편리하다.
서비스는 운영체제가 시작할 때 자동으로 실행할 수 있게 설정하고, 작업 관리자에 프로세스로 보이지 않을 수도 있다.
함수 | 설명 | |
OpenSCManager | 서비스 제어 관리자(Service Control Manager)에 핸들을 반환하며, 모든 이후 서비스 관련 함수 호출에 사용된다. 서비스와 상호작용하는 모든 코드는 이 함수를 호출한다 | |
CreateService | 서비스 제어 관리자에 신규 서비스로 등록하고, 부팅 시 서비스의 자동 시작 또는 수동 시작 여부를 호출자가 지정할 수 있게 한다. | |
StartService | 서비스를 시작하고 서비스가 수동으로 시작하게 설정돼 있을 때만 사용된다. |
악성코드가 가장 흔히 사용하는 방식은 WIN32_SHARE_PROCESS 유형으로 DLL에 서비스 코드를 저장하고, 하나의 공유 프로세스에 다른 서비스와 결합한다. svchost.exe 프로세스는 WIN32_SHARE_PROCESS 유형의 서비스로 실행하는 것이다.
WIN32_OWN_PROCESS 유형은 .exe 파일 내에 코드를 저장하고 독립적인 프로세스로 실행할 수 있기 때문에 사용하기도 한다.
마지막으로 자주 사용되는 서비스 유형은 KERNEL_DRIVER로 커널에 코드를 로딩할 때 사용한다.
로컬 시스템에서 서비스 정보는 레지스트리에 저장되며 각 서비스는 HKLM\SYSTEM\CurrentControlSet\Services 내에 서브키를 가진다.
'정보보안 > Malware' 카테고리의 다른 글
[Malware] Flare VM을 이용한 악성코드 분석환경 구축 (0) | 2021.07.11 |
---|---|
[Reversing] 컴포넌트 객체 모델(COM) (0) | 2021.06.02 |
[Reversing] 윈도우 커널 모드와 사용자 모드 (0) | 2021.06.01 |
[Reversing] 리버싱을 위한 윈도우 API 기초 (0) | 2021.05.14 |
[Reversing] 어셈블리어 기본 명령어 (0) | 2021.05.13 |