Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
도구/GitHubGitHub/qmonnet/rbpf
Embedded Systems SecurityPacket Sniffing & AnalysisDynamic Analysis (Sandboxing)Reverse EngineeringNetwork SecurityUtilities & FrameworksBinary Analysis
GitHubqmonnet/rbpf

rbpf

eBPF 프로그램을 위한 Rust 가상 머신 및 JIT 컴파일러

저장소 보기
1.1k3774개월 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

rbpf

eBPF를 위한 Rust (사용자 공간) 가상 머신

Build Status Build status Coverage Status Crates.io

  • 설명
  • crate 링크
  • API
  • 사용 예시
  • eBPF 프로그램 빌드
  • 빌드 기능
  • 피드백 환영!
  • 질문 / 답변
  • 주의사항
  • To do 목록
  • 라이선스
  • 영감을 받은 곳
  • 기타 자료

설명

이 crate는 eBPF 프로그램 실행을 위한 가상 머신을 포함합니다. BPF는 _Berkeley Packet Filter_의 약자로, 원래 BSD 시스템을 위해 개발된 어셈블리와 유사한 언어로, tcpdump와 같은 도구를 사용하여 커널에서 패킷을 필터링함으로써 사용자 공간으로의 불필요한 복사를 피하기 위한 것입니다. 이는 Linux로 이식되었고, 더 빠르고 더 많은 기능을 갖춘 버전인 eBPF(extended BPF)로 발전했습니다. BPF 프로그램은 원래 커널에서 실행되도록 설계되었지만, 이 crate의 가상 머신은 사용자 공간 애플리케이션에서 실행할 수 있게 해줍니다. 여기에는 인터프리터, eBPF 프로그램을 위한 x86_64 JIT 컴파일러, 그리고 디스어셈블러가 포함되어 있습니다.

이는 거의 동일한 기능을 하지만 C로 작성된 Rich Lane의 uBPF 소프트웨어를 기반으로 합니다.

이 crate는 Linux, MacOS X, Windows에서 컴파일 및 실행되어야 하지만, JIT 컴파일러는 현재 Windows에서 작동하지 않습니다.

crate 링크

이 crate는 crates.io에서 사용할 수 있으므로, Cargo.toml 파일에 의존성으로 추가하면 바로 작동할 것입니다:

[dependencies]
rbpf = "0.4.1"

개발 버전은 이 GitHub 저장소에서도 사용할 수 있습니다. 이는 Cargo.toml 안에 다음을 넣는 것만큼 간단해야 합니다:

[dependencies]
rbpf = { git = "https://github.com/qmonnet/rbpf" }

물론, 원한다면 로컬에 클론하여 크레이트를 수정한 뒤, Cargo.toml에 로컬 버전의 경로를 지정할 수도 있습니다:

[dependencies]
rbpf = { path = "path/to/rbpf" }

그런 다음 소스 코드에서 해당 crate를 사용하겠다고 명시하세요:

extern crate rbpf;

API

API는 소스 코드 내에 상당히 잘 문서화되어 있습니다. 또한 여기에서 온라인 버전의 문서에 접근할 수 있으며, 이는 crates.io 버전에서 자동 생성된 것입니다(메인 브랜치와 최신 상태가 아닐 수 있음). 예제와 단위 테스트도 도움이 될 것입니다. 다음은 이 크레이트를 사용하는 방법에 대한 요약입니다.

rbpf로 eBPF 프로그램을 실행하기 위해 따라야 할 단계는 다음과 같습니다:

  1. 가상 머신을 생성합니다. 여러 종류의 머신이 있으며, 이에 대해서는 나중에 다시 설명하겠습니다. VM을 생성할 때 eBPF 프로그램을 생성자에 인수로 전달합니다.
  2. 일부 헬퍼 함수를 사용하려면 가상 머신에 등록합니다.
  3. JIT 컴파일된 프로그램을 원한다면 컴파일합니다.
  4. 프로그램을 실행합니다: 인터프리터를 실행하거나 JIT 컴파일된 함수를 호출합니다.

eBPF는 처음에 패킷을 필터링하도록 설계되었습니다(현재는 Linux 커널에 kprobes와 같은 다른 훅이 있지만, 이는 rbpf에서 다루지 않습니다). 결과적으로 프로그램의 대부분의 로드 및 저장 명령은 패킷 데이터를 나타내는 메모리 영역에서 수행됩니다. 그러나 Linux 커널에서 eBPF 프로그램은 이 데이터 영역에 즉시 접근하지 않습니다: 처음에는 C struct sk_buff에 접근할 수 있으며, 이는 패킷에 대한 메타데이터—패킷 데이터 영역의 시작과 끝의 메모리 주소를 포함—를 담고 있는 버퍼입니다. 따라서 프로그램은 먼저 sk_buff에서 해당 포인터를 로드한 다음 패킷 데이터에 접근할 수 있습니다.

이 동작은 rbpf로 복제할 수 있지만 필수는 아닙니다. 이러한 이유로 다양한 종류의 가상 머신을 나타내는 여러 구조체가 있습니다:

  • struct EbpfVmMbuffer는 커널을 모방합니다. 프로그램이 실행될 때, 첫 번째 eBPF 레지스터에 제공되는 주소는 사용자가 제공한 메타데이터 버퍼의 주소가 되며, 이 버퍼는 패킷 데이터 메모리 영역의 시작과 끝에 대한 포인터를 포함할 것으로 예상됩니다.

  • struct EbpfVmFixedMbuff는 한 가지 목적을 가지고 있습니다: 커널과 호환되도록 생성된 프로그램의 실행을 가능하게 하면서, 사용자가 메타데이터 버퍼를 수동으로 처리하는 수고를 덜어줍니다. 실제로 이 구조체는 프로그램에 전달되는 정적 내부 버퍼를 가지고 있습니다. 사용자는 eBPF 프로그램이 버퍼에서 패킷 데이터의 시작과 끝을 찾을 것으로 예상하는 오프셋 값을 지정해야 합니다. 프로그램을 실행하는 함수를 호출할 때(JIT 여부와 관계없이), 이 구조체는 프로그램이 호출되는 패킷 데이터의 시작과 끝에 대해 지정된 오프셋에서 이 정적 버퍼의 주소를 자동으로 업데이트합니다.

  • struct EbpfVmRaw는 패킷 데이터에서 직접 실행하려는 프로그램을 위한 것입니다. 메타데이터 버퍼가 관여하지 않으며, eBPF 프로그램은 첫 번째 레지스터에서 패킷 데이터의 주소를 직접 받습니다. 이것이 uBPF의 동작입니다.

  • struct EbpfVmNoData는 어떤 데이터도 받지 않습니다. eBPF 프로그램은 어떤 인수도 받지 않으며 반환 값은 결정적입니다. 이에 대한 유효한 사용 사례가 있을지는 확실하지 않지만, 적어도 단위 테스트에 매우 유용합니다.

이 모든 구조체는 동일한 공용 함수를 구현합니다:

// called with EbpfVmMbuff:: prefix
pub fn new(prog: &'a [u8]) -> Result<EbpfVmMbuff<'a>, Error>

// called with EbpfVmFixedMbuff:: prefix
pub fn new(prog: &'a [u8],
           data_offset: usize,
           data_end_offset: usize) -> Result<EbpfVmFixedMbuff<'a>, Error>

// called with EbpfVmRaw:: prefix
pub fn new(prog: &'a [u8]) -> Result<EbpfVmRaw<'a>, Error>

// called with EbpfVmNoData:: prefix
pub fn new(prog: &'a [u8]) -> Result<EbpfVmNoData<'a>, Error>

이는 VM의 새 인스턴스를 생성하는 데 사용된다. 반환 타입은 함수가 호출된 구조체에 따라 달라진다. 예를 들어, rbpf::EbpfVmRaw::new(Some(my_program))는 struct rbpf::EbpfVmRaw의 인스턴스(Result로 감싸진)를 반환한다. 프로그램이 로드되면, 매우 단순한 검증기(Linux 커널용 검증기와는 전혀 다른)로 검사된다. 사용자는 이를 사용자 정의 검증기로 대체할 수도 있다.

struct EbpfVmFixedMbuff의 경우, 생성자에 두 개의 추가 인자가 전달되어야 한다: data_offset과 data_end_offset이다. 이들은 프로그램이 실행될 때마다 패킷 데이터의 메모리 영역 시작과 끝을 가리키는 포인터가 내부 메타데이터 버퍼에 저장될 오프셋(바이트 번호)이다. 다른 구조체들은 이 메커니즘을 사용하지 않으며 해당 오프셋이 필요하지 않다.

// for struct EbpfVmMbuff, struct EbpfVmRaw and struct EbpfVmRawData
pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error>

// for struct EbpfVmFixedMbuff
pub fn set_program(&mut self, prog: &'a [u8],
                data_offset: usize,
                data_end_offset: usize) -> Result<(), Error>

예를 들어 my_vm.set_program(my_program);를 사용하여 VM 인스턴스 생성 후 로드된 프로그램을 변경할 수 있습니다. 이 프로그램은 VM에 연결된 검증기로 검사됩니다. VM의 검증 함수는 언제든지 변경할 수 있습니다.

pub type Verifier = fn(prog: &[u8]) -> Result<(), Error>;

pub fn set_verifier(&mut self,
                    verifier: Verifier) -> Result<(), Error>

프로그램이 이미 VM에 로드된 경우, 새 검증기를 설정하면 로드된 프로그램에서 즉시 실행된다는 점에 유의하십시오. 그러나 프로그램이 로드되지 않은 경우(VM을 생성할 때 new() 메서드에 None이 전달된 경우)에는 검증기가 실행되지 않습니다.

pub type Helper = fn (u64, u64, u64, u64, u64) -> u64;

pub fn register_helper(&mut self,
                       key: u32,
                       function: Helper) -> Result<(), Error>

이 함수는 헬퍼 함수를 등록하는 데 사용됩니다. VM은 레지스터를 해시맵에 저장하므로, 키는 원하는 어떤 u32 값이든 될 수 있습니다. 이는 Linux 커널과 호환되어야 하므로 특정 헬퍼 번호를 사용해야 하는 프로그램에 유용할 수 있습니다.

pub fn register_allowed_memory(&mut self, addrs_range: Range<u64>) -> ()

이 함수는 eBPF 프로그램이 로드하고 저장할 수 있는 메모리 주소 목록을 추가합니다. 이 함수를 여러 번 호출하면 주소가 내부 HashSet에 추가됩니다. 현재 rbpf는 인터프리터를 사용할 때만 메모리 접근을 검증합니다. 이 함수는 eBPF 맵에 저장된 객체에 대한 포인터를 반환하는 커널 헬퍼를 사용할 때 유용합니다.

// for struct EbpfVmMbuff
pub fn execute_program(&self,
                 mem: &'a mut [u8],
                 mbuff: &'a mut [u8]) -> Result<(u64), Error>

// for struct EbpfVmFixedMbuff and struct EbpfVmRaw
pub fn execute_program(&self,
                 mem: &'a mut [u8]) -> Result<(u64), Error>

// for struct EbpfVmNoData
pub fn execute_program(&self) -> Result<(u64), Error>

로드된 프로그램을 해석합니다. 이 함수는 사용된 VM의 종류에 따라 패킷 데이터와 메타데이터 버퍼에 대한 참조를 받거나, 패킷 데이터에 대한 참조만 받거나, 아무것도 받지 않습니다. 반환되는 값은 eBPF 프로그램의 결과입니다.

pub fn jit_compile(&mut self) -> Result<(), Error>

로드된 프로그램을 x86_64 아키텍처용으로 JIT 컴파일합니다. 프로그램이 헬퍼 함수를 사용해야 하는 경우, 이 함수가 호출되기 전에 VM에 등록되어야 합니다. 생성된 어셈블리 함수는 내부적으로 VM에 저장됩니다.

// for struct EbpfVmMbuff
pub unsafe fn execute_program_jit(&self, mem: &'a mut [u8],
                            mbuff: &'a mut [u8]) -> Result<(u64), Error>

// for struct EbpfVmFixedMbuff and struct EbpfVmRaw
pub unsafe fn execute_program_jit(&self, mem: &'a mut [u8]) -> Result<(u64), Error>

// for struct EbpfVmNoData
pub unsafe fn execute_program_jit(&self) -> Result<(u64), Error>

JIT 컴파일된 프로그램을 호출합니다. 제공할 인수는 execute_program()과 동일하며, 이는 사용되는 VM의 종류에 따라 달라집니다. JIT 컴파일된 프로그램의 결과는 인터프리터와 동일해야 하지만, 더 빠르게 실행되어야 합니다. 프로그램 실행 중 오류가 발생하면 JIT 컴파일된 버전은 인터프리터만큼 잘 처리하지 못하며 프로그램이 충돌할 수 있다는 점에 유의하십시오. 이러한 이유로 해당 함수들은 unsafe로 표시되어 있습니다.

사용 예시

간단한 예시

이는 단위 테스트 test_vm_add에서 가져온 것입니다.

extern crate rbpf;

fn main() {
도구 다운로드