Computer >> 컴퓨터 >  >> 시스템 >> Mac

컴퓨터 RAM 데이터를 읽고 분석하는 방법: LiME 활용 실전 가이드

이 글은 컴퓨터 RAM(Random Access Memory)의 내용을 직접 읽고 분석하는 방법을 다루는 종합 가이드입니다.

RAM은 모든 컴퓨터 시스템에서 핵심적인 역할을 하는 부품으로, 시스템이 작업을 수행하는 데 필요한 데이터를 일시적으로 저장합니다. 하지만 RAM의 내용은 휘발성이 강해서 시스템이 종료되면 대부분 사라지게 됩니다.

이렇게 사라지기 전에 RAM의 내용을 보존하는 방법 중 하나가 바로 RAM 덤프(RAM dump)입니다. RAM 덤프란 RAM에 저장된 내용을 하드 드라이브 같은 저장 장치로 복사하는 과정을 말합니다. 덤프된 데이터를 분석하면 덤프가 수행된 시점의 시스템 상태에 대한 귀중한 정보를 얻을 수 있습니다.

이 글에서는 RAM의 내용을 읽는 전체 과정을 단계별로 살펴보고, RAM 덤프가 무엇인지, 그리고 이것이 컴퓨터 시스템 분석에 어떻게 유용하게 쓰일 수 있는지 설명합니다.

왜 RAM 데이터를 읽어야 할까?

디스크에서 데이터를 읽어오는 것은 누구나 해본 경험이 있을 겁니다. 그런데 가장 핵심적인 정보가 저장되어 있는 RAM에서도 데이터를 직접 읽을 수 있을까요?

개발자라면 공간 복잡도(space complexity)를 조사하기 위해 RAM 깊숙이 들여다보며 무슨 일이 벌어지고 있는지 파악할 수 있습니다.

RAM에 접근해 내용을 읽는 것은 다양한 상황에서 유용합니다. 대표적인 활용 사례는 컴퓨터 시스템의 문제를 진단하고 트러블슈팅하는 것입니다. RAM의 내용을 검토하면 특정 시점의 시스템 상태를 파악할 수 있습니다. 예를 들어 컴퓨터가 갑자기 크래시되었을 때, RAM 내용을 확인하면 크래시의 원인을 찾는 데 도움을 받을 수 있습니다.

또 다른 활용 사례는 포렌식(forensic) 분석입니다. 부정 행위의 증거를 찾기 위해 컴퓨터 시스템을 조사할 때 RAM 내용을 분석하면 해당 시스템에서 수행된 활동에 대한 중요한 단서를 얻을 수 있습니다. 예를 들어 보안 전문가는 RAM 분석을 통해 특정 프로세스가 실행 중이었는지 확인하거나 최근에 접근된 파일을 식별할 수 있습니다.

그뿐만 아니라 소프트웨어 개발자와 연구자에게도 유용합니다. 개발자는 RAM에 저장된 데이터를 분석해 자신이 만든 소프트웨어의 성능을 점검하고 잠재적 문제나 병목 지점을 발견할 수 있습니다. 연구자들은 RAM 분석을 활용해 악성코드의 동작 방식을 연구하거나 새로운 보안 도구와 기법을 개발하기도 합니다.

정리하면, RAM 데이터를 읽는 것은 트러블슈팅, 포렌식 분석, 소프트웨어 개발, 연구 등 여러 분야에서 시스템 내부 동작을 들여다볼 수 있는 강력한 수단입니다.

본격적으로 들어가기 전에 용어부터 간단히 짚고 넘어가겠습니다. 이미 알고 있는 내용일 수 있지만, 이 가이드를 따라가려면 반드시 이해해야 하는 개념들이므로 한 번 정리할 가치가 있습니다.

먼저 RAM(랜덤 액세스 메모리)이라는 물리적 하드웨어 장치, 즉 물리 메모리가 있습니다. CPU, 하드 디스크 등 다른 물리 구성 요소들도 함께 존재합니다.

그 위에서 운영체제가 동작합니다. 운영체제는 '커널(kernel)'이라 불리는 하드웨어와 끊임없이 소통하는데, 커널은 운영체제 소프트웨어에서 가장 중요한 부분 중 하나입니다.

사용자 관점에서 보면, 우리는 운영체제에 로그인해 다양한 작업을 수행하며, 그 대부분은 애플리케이션을 실행하는 일입니다.

커널(Kernel)이란?

커널은 운영체제의 핵심 부분으로, 사용자가 실행하는 프로그램을 뒷받침하면서 사용자의 명령을 받아 처리합니다.

모든 연산은 CPU(중앙처리장치)가 담당하지만, 우리가 무엇을 하든 CPU가 제공하는 서비스를 어떻게 활용하든, 데이터·명령어·코드·프로그램은 모두 RAM을 거쳐야 합니다.

즉, 어느 순간 데이터로 수행한 작업의 결과물은 모두 메모리 위에 존재한다는 뜻입니다. 프로그래머 입장에서 어떤 자료구조(data structure)를 만든다면, 그 데이터는 모두 RAM 위에 올라가 있는 것입니다.

따라서 RAM으로 직접 가서 자료구조가 어떻게 생성되고 어떻게 정렬(align)되는지, 공간 복잡도가 실제로 어떻게 작동하는지 확인할 수 있습니다.

예를 들어 Chrome 같은 웹 브라우저에서 보안 취약점이 발생했다고 가정해 봅시다. 이럴 때 가장 효과적인 방법은 RAM으로 들어가 데이터가 실제로 어떻게 동작하는지 조사하는 것입니다.

Chrome(또는 어떤 브라우저든)에서 gmail.com 같은 보안 웹사이트를 연다고 해봅시다. Gmail에 입력하는 아이디와 비밀번호를 포함한 모든 정보는 인터넷을 통해 Google의 서버로 전송됩니다. 이 데이터는 완전히 암호화되어 있기 때문에 비밀번호를 해독하는 것은 매우 어렵거나 사실상 불가능합니다.

하지만 비밀번호를 입력하려면 키보드가 달린 컴퓨터를 사용해야겠죠? 입력된 후에야 어떤 프로그램이 그 데이터를 암호화해서 인터넷으로 전송합니다. 즉, 처음에는 당신의 데이터가 RAM 위에 존재했던 것입니다.

비밀번호는 우선 평문(plain text) 형태의 데이터이며, 이 비밀번호가 RAM 위에 먼저 저장됩니다. 그다음 프로그램이 데이터를 암호화해 인터넷으로 전송하는 것이죠. 만약 RAM에 접근할 수 있다면, 비밀번호가 실제로 암호화되었는지 직접 확인해볼 수 있습니다. 생각보다 간단한 과정입니다.

예시를 하나 들어 보겠습니다. 변수 'a'에 데이터 '9'가 있다고 합시다. 프로그램을 실행하면 이 데이터가 RAM에 로드됩니다. 프로그램이 끝나면 RAM의 데이터는 사라진다고 알려져 있지만, 아직 아무도 이를 엄밀히 증명하지 않았습니다. 다만 실제로 그렇고, 간단한 실험으로 증명할 수 있습니다.

메모리 맨 위에 로드되었던 데이터가 애플리케이션 실행이 끝난 후에도 RAM에 남아 있는지 어떻게 확인할 수 있을까요?

사실 RAM의 내용은 곧 지워집니다. 이때 RAM 덤프란 RAM 전체를 그대로 포착하는 작업을 의미합니다. 데이터 세트가 처음 RAM에 로드되고 접근 가능한 형태 그대로를 보여주는 것이죠. 다음으로 이 데이터를 메모리에서 어떻게 포착하고 추출하는지 알아보겠습니다.

이를 위해서는 어떤 형태의 소프트웨어가 필요합니다. 이 소프트웨어의 목표는 메모리 더 깊은 곳까지 탐색하여, 메모리에 저장된 모든 데이터를 가져오는 것입니다.

LiME란?

LiME(Linux Memory Extractor, 리눅스 메모리 추출기)는 강력한 소프트웨어로, 리눅스에서 메모리를 추출할 때 사용하는 도구입니다. 이 소프트웨어는 드라이버(driver), 또는 모듈(module)이라고도 불립니다. RAM이 하나의 장치(device)이기 때문인데, 이 때문에 상황이 좀 더 복잡해집니다.

장치에 접근해서 내용을 읽으려면 일종의 드라이버가 필요합니다. LiME가 바로 그런 드라이버의 예입니다. 리눅스에 익숙하다면 드라이버가 동작하려면 커널의 도움을 받아 해당 드라이버를 로드해야 한다는 점을 알고 있을 겁니다.

리눅스 환경에서 드라이버는 모듈이라고도 부릅니다. 따라서 LiME는 리눅스 커널 모듈입니다. 우리에게는 커널 로더블 모듈(loadable kernel module)이라는 것이 제공되며, 이를 통해 운영체제에 모듈을 설치할 수 있습니다.

배경 설명은 충분합니다. 이제 RAM의 내용을 실제로 추출하는 방법을 단계별로, 실습 형식으로 살펴보겠습니다.

환경 설정 및 설치

필요한 것은 오직 LiME 드라이버 하나뿐입니다. 이 모듈은 https://github.com/gursimarsm/LiME 에서 다운로드할 수 있습니다.

리눅스 시스템을 부팅하세요(본 예제는 Red Hat Enterprise Linux를 사용했습니다). free -h 명령어를 입력하면 사용 중인 RAM 용량, 가용 용량 등 세부 정보를 확인할 수 있습니다. 결과는 다음과 같습니다.

free -m 명령 실행 결과

RAM에 접근하려면 커널이 추가 모듈을 로드할 수 있는 소프트웨어가 필요합니다. 여기서 필요한 모듈 이름은 LiME입니다. 이를 위해 설치해야 할 패키지는 'kernel-devel'과 'kernel-headers' 두 가지입니다. 이 두 소프트웨어가 있어야 LiME 모듈을 사용할 준비가 됩니다.

소프트웨어를 설치하려면 'yum'이 설정되어 있어야 합니다. 참고로 yum은 Red Hat 계열 리눅스에서 소프트웨어를 설치할 때 사용하는 명령어입니다. 설정 방법은 글 말미의 부록에서 다룹니다.

설치가 끝났다면 한 가지 더 준비물이 있습니다. GitHub에서 드라이버를 다운로드해야 하기 때문에 Git이 없다면 설치해야 합니다. yum install git 명령어로 설치할 수 있으며, 계정도 미리 설정해두는 것이 좋습니다.

# git config --global user.name "Your Name" 
# git config --global user.email "you@example.com"

앞서 소개한 저장소는 로더블 커널 모듈(LKM, Loadable Kernel Module)입니다. 이 모듈을 사용하면 리눅스 운영체제 전체 메모리를 확보할 수 있으며, 리눅스 기반의 다른 운영체제(안드로이드 역시 리눅스 기반이므로 안드로이드 기기 포함)에서도 사용할 수 있습니다.

아래 명령어로 모듈을 클론(clone)합니다.

# git clone https://github.com/gursimarsm/LiME

다운로드 후에는 해당 소프트웨어의 디렉터리로 이동합니다. 폴더가 여러 개 보이는데, 메인 코드를 실행하려면 'src' 디렉터리로 들어가야 합니다.

이 디렉터리에는 C 언어로 작성된 여러 파일이 있습니다. 이 파일들을 사용하려면 컴파일이 필요합니다. make 명령어를 사용하면 되는데, 먼저 다음과 같이 설치합니다.

# yum install make 
# yum install gcc

/LiME/src/ 디렉터리에서 make 명령을 실행하면 전체 코드가 컴파일됩니다.

만약 오류가 발생한다면, 최신 버전의 LiME에 포함된 새로운 기능인 ORC 메타데이터 생성(orc metadata generate) 때문일 가능성이 높습니다. 이 기능을 사용하려면 LiME의 구성 요소인 elfutils-libelf-devel을 추가로 설치해야 합니다. yum으로 다음과 같이 설치할 수 있습니다.

elfutils-libelf-devel 설치 방법

설치가 완료되면 다시 make 명령을 실행합니다. GCC 컴파일러가 전체 코드를 컴파일하고, 마지막에 커널 오브젝트 파일(kernel object file)이라는 최종 파일이 생성됩니다. 이것이 LiME의 최종 모듈입니다.

같은 디렉터리에서 ls 명령어로 이 파일을 확인할 수 있습니다.

모듈 사용 방법

이 모듈을 로드하면 커널이 RAM 전체를 포착하거나 읽을 수 있게 됩니다. 기본적으로는 RAM 전체를 한 번에 읽을 수 없지만, LiME 모듈 덕분에 가능해집니다.

LiME 모듈에 대해 더 자세히 알고 싶다면 modinfo 명령어를 사용하세요. 이 명령은 파일 위치 정보를 보여줄 뿐만 아니라, 추가 파라미터를 가진 모듈(드라이버)들의 목록도 표시합니다. 각 파라미터마다 고유한 용도가 있습니다.

여기서는 두 가지 핵심 파라미터를 사용합니다: pathformat.

path는 RAM 전체를 읽은 후 데이터를 저장할 파일을 지정하는 옵션입니다. 생성하고자 하는 목적 파일의 경로를 이곳에 지정합니다.

다음 파라미터 format은 RAM 데이터를 어떤 형식으로 읽을지 지정합니다. 여기서는 RAM에 저장된 형태 그대로를 읽기를 원합니다. RAM에 저장된 데이터는 대부분 2진수(binary) 형태이며, 우리는 전체 데이터를 그대로 원형(raw form)으로 포착하고 싶습니다.

따라서 format은 raw로 지정하고, path로 지정한 파일에 저장하면 됩니다.

이제 드디어 RAM에서 데이터를 읽어낼 차례입니다. RAM 전체를 읽기 시작하는 핵심 명령어를 살펴보겠습니다.

실습 데모

이 데모에서는 Chrome에서 Gmail 계정의 비밀번호를 입력해 봅니다. 이를 통해 RAM에서 데이터를 어떻게 포착하는지, 그리고 비밀번호가 실제로 암호화되었는지 확인하는 방법을 배울 수 있습니다.

이 두 가지를 검증하려면 명령 프롬프트로 이동해 해당 데이터가 아직 RAM에 남아 있는지 확인해야 합니다. 특정 모듈을 로드하려면 insmod 명령어를 사용합니다. 이 명령어가 모듈을 삽입해 줍니다.

모듈의 전체 경로를 복사한 뒤 insmod 명령어와 함께 붙여 넣습니다.

insmod 명령어

커널의 도움으로 모듈이 로드되면, 모듈은 RAM의 전체 데이터를 포착하기 시작해 예를 들어 myram.data 같은 파일에 저장합니다.

메모리 덤프(RAM 덤프) 전체가 이 파일에 로드되며, 어떤 형식으로 포착할지도 지정합니다. 여기서는 raw 형식을 사용합니다.

이 두 파라미터만 지정하면 됩니다(지금은 세부 사항을 걱정하지 않아도 됩니다). 명령어를 실행하는 순간 RAM에 있는 모든 데이터가 지정한 파일에 포착되어 저장됩니다. 이 명령은 일반적으로 몇 초 정도 걸리며, CPU 속도와 RAM에 있는 데이터 양에 따라 소요 시간이 달라집니다.

명령어 실행

데이터를 읽는 방법

이제 myram.data 파일이 생겼고, RAM의 전체 데이터가 이 파일에 저장되어 있습니다. 데이터를 raw 형식으로 포착했기 때문에 파일 안의 데이터는 2진수 형태입니다. 사람이 이 파일을 직접 읽으려 해도, head 명령어로 첫 10줄만 읽어봐도 알아볼 수 없습니다.

출력 결과

'cat' 명령어를 사용하면 전체 데이터를 읽을 수 있지만, 마찬가지로 데이터가 2진수 형태로 표시될 뿐입니다. 그래서 이 명령어에 파이프(pipe) 기능을 결합해 strings라는 또 다른 명령어와 연결합니다.

명령어

strings는 데이터를 사람이 읽을 수 있는 일반 텍스트로 변환해 주는 명령어입니다.

출력 결과

목록은 끝없이 이어질 수 있으며, Ctrl+C로 언제든 중단할 수 있습니다.

지금 상태로는 전체 데이터를 훑어봐야 큰 의미를 찾기 어렵습니다. RAM에 'mywebpasswordgmail'이라는 비밀번호 데이터가 있다는 것을 우리는 알고 있습니다. 이 데이터가 실제로 RAM에 존재하는지 확인하려면 파이프를 하나 더 연결해 grep 명령어를 사용하면 됩니다. grep은 데이터를 필터링해 주는 도구입니다.

cat /myram.data | strings | grep mywebpasswordgmail

이제 전체 데이터에서 이 문자열을 검색합니다. 데이터가 일반 텍스트로 변환되고, 해당 문자열이 나타나는 줄을 grep이 잡아내 화면에 보여줍니다.

이 간단한 예시에서 볼 수 있듯이, 키보드로 입력하는 모든 내용은 RAM에 기록됩니다. 비밀번호든, 보안 사이트를 탐방하든 상관없습니다. 어떤 프로그램을 실행하든 키보드로 입력한 모든 것은 RAM에 로드되며, 추출될 수 있습니다. 이것이 바로 메모리 덤프(memory dump)입니다.

LiME는 그 외에도 강력한 기능을 많이 제공합니다. 지금은 작업을 수행하는 시스템에서 직접 데이터를 포착했지만, LiME를 시스템에서 실행해 실시간으로 데이터를 포착한 뒤 네트워크를 통해 다른 컴퓨터로 전송하는 것도 가능합니다.

이게 무슨 뜻일까요? 예를 들어 누군가 웹사이트를 열고 실시간으로 무언가를 입력하고 있다고 상상해 보세요. 그 입력 내용 전체가 실시간으로 다른 컴퓨터로 전송되는 것입니다.

여기서 이야기하는 것은 키로거(keylogger)가 아니라 어디까지나 RAM입니다. 어떤 프로그램이 실행되는 동안 벌어지는 모든 일, 데이터베이스가 데이터를 저장하는 작업, 프로그램이 하드 디스크의 다른 영역에서 데이터를 읽는 작업 등 RAM 위에서 일어나는 모든 활동을 실시간으로 포착해 네트워크를 통해 다른 컴퓨터로 보낼 수 있습니다.

마무리

이 글이 도움이 되었기를 바랍니다. RAM 덤프와 LiME 모듈의 원리, 그리고 실전 활용 방법까지 함께 살펴보았습니다.

궁금한 점이나 제안이 있다면 LinkedIn을 통해 언제든 메시지를 보내주세요.

이 글이 유용했다면 GitHub에 스타를 남기거나 LinkedIn에서 관련 스킬에 대한 추천(endorsement)을 남겨주시면 큰 힘이 됩니다.

다음 글에서 만나요. 항상 안전하고 꾸준히 학습하시길 바랍니다.