
Ghidra를 위한 바이너리 코드 커버리지 시각화 플러그인
Dragon Dance는 Ghidra 플러그인으로, 바이너리 코드 커버리지 데이터를 시각화하고 조작할 수 있게 해줍니다. 여러 커버리지 소스에서 커버리지 데이터를 가져올 수 있습니다. 현재 플러그인은 Dynamorio와 Intel Pin 바이너리 계측 도구를 지원합니다. Dynamorio는 "drcov"라는 자체 커버리지 수집 모듈을 가지고 있습니다. Intel Pin은 내장 커버리지 수집 모듈을 제공하지 않습니다. 이 부재 상황을 처리하기 위해 Intel Pin용 자체 커버리지 수집 모듈을 작성해야 했습니다. 그래서 ddph(Dragon Dance Pin Helper)라는 Intel Pin용 커버리지 수집 모듈을 작성했습니다. 이를 사용할 수 있습니다. ddph의 소스 코드는 이 링크에서 볼 수 있습니다. 직접 컴파일하기 귀찮다면 Windows, macOS, Linux용으로 제공된 컴파일된 바이너리를 사용할 수 있습니다.

Dragon Dance는 동일한 세션에서 여러 커버리지 데이터를 가져와 사용할 수 있습니다. (멀티 세션도 지원하지만 현재 GUI에서는 사용할 수 없습니다). 그리고 그들 사이를 전환하거나 교차, 차이, 고유 또는 합 연산을 서로 빠르게 적용할 수 있습니다.
Dragon Dance를 통해 실행된 명령어의 강도를 볼 수 있습니다. 따라서 어떤 명령어가 얼마나 자주 실행되었는지 힌트를 얻을 수 있습니다. 또한 함수 그래프 창에서 커버리지 시각화를 볼 수 있습니다.

Dragon Dance는 자체 스크립팅 시스템도 지원합니다.

커버리지 데이터를 유연하게 다룰 수 있게 해줍니다. 데이터를 로드, 삭제, 표시, 교차, 차이, 고유, 합 연산을 수행할 수 있습니다. 다음 섹션에는 스크립팅 시스템과 API가 포함됩니다. 스크립트를 실행하려면 Alt + Enter 키를 누르세요.
내장 함수는 스크립팅 시스템에 인터페이스를 제공하기 위한 내부 커버리지 연산의 구현입니다. 내장 함수는 커버리지 객체 변수를 반환하거나 아무 것도 반환하지 않을 수 있습니다. 내장 함수는 별칭을 가질 수 있습니다.
이들은 매개변수로 내장 인수를 받습니다. 매개변수는 가변 길이일 수 있습니다.
내장 인수는 다양한 값 유형을 보유하는 참조입니다. 내장 인수는 왼쪽에서 오른쪽 순서로 전달됩니다. 내장 인수는 다음 값 유형을 보유할 수 있습니다:
변수는 커버리지 객체만 보유하는 역할을 합니다. 내장 함수에 의해 로드될 수 있습니다. 내장 함수에 매개변수(내장 인수)로 전달될 수 있습니다.
두 가지 유형의 커버리지 객체가 있습니다.
물리적 커버리지 객체와 논리적 커버리지 객체
물리적 커버리지 객체는 커버리지 파일에서 직접 로드된 커버리지 객체를 가리킵니다. 이들은 GUI의 커버리지 테이블에 표시되며 GUI 작업을 통해 상호 작용할 수 있습니다.
논리적 커버리지 객체는 내장 함수에서 처리되어 결과로 반환된 커버리지 객체를 가리킵니다. 이들은 GUI에 표시되지 않지만 소멸될 때까지 변수에 존재할 수 있습니다.
커버리지 객체는 두 유형 모두에 대해 변수 객체에 의해 자동으로 유지 관리됩니다. 예를 들어;``` cov1 = load("firstcoverage.out") cov2 = load("secondcov.out")
cov1 = diff(cov1,cov2)
이 예제에서 cov1과 cov2는 변수입니다. 그리고 두 변수 모두 물리적 커버리지 객체를 가지고 있습니다. diff 내장 함수는 두 변수를 가져와서 반환 값을 cov1 변수에 설정합니다. 이 덮어쓰기 연산은 결과 커버리지 객체를 변수에 설정하지만, 해당 객체가 물리적 커버리지 객체이기 때문에 커버리지 객체를 삭제하지는 않습니다. 해당 커버리지 데이터는 세션과 GUI 테이블에 계속 남아 있습니다.
이전 예제를 이렇게 생각해 봅시다;```
cov1 = load("first.out")
cov2 = load("second.out")
cov3 = load("third.out")
rvar = sum(cov1,cov2,cov3)
rvar = diff(rvar, cov2)
In this example three physical coverage variable goes into sum operation and the sum operation returns logical result coverage object. Then the diff operation takes a logical and a physical variable in it and overwrites the variable named rvar.
이 예제에서는 세 개의 물리적 커버리지 변수가 sum 연산에 들어가고, sum 연산은 논리적 결과 커버리지 객체를 반환합니다. 그런 다음 diff 연산은 논리적 변수와 물리적 변수를 입력으로 받아 rvar라는 변수를 덮어씁니다.
In this case, the result will be set to the rvar and it's previous coverage value destroyed immediately. Because this was a logical object and should be deleted to prevent object leakage. If you want to destroy a variable that it contained a physical coverage object, you have to call discard built-in to do. All built-ins will be detailed below.
이 경우 결과는 rvar에 설정되고 이전 커버리지 값은 즉시 제거됩니다. 이는 논리적 객체였기 때문에 객체 누출을 방지하기 위해 삭제되어야 하기 때문입니다. 만약 물리적 커버리지 객체를 포함한 변수를 삭제하려면 내장 함수 discard를 호출해야 합니다. 모든 내장 함수는 아래에서 자세히 설명합니다.
You can write complex scripts using nested built-in calls, you can write something like so:
중첩된 내장 함수 호출을 사용하여 복잡한 스크립트를 작성할 수 있습니다. 예를 들어 다음과 같이 작성할 수 있습니다.
cres = diff(intersect(a, load("another.log"), c, d), sum(e,f) )
you don't have to write the logic line by line.
로직을 한 줄씩 작성할 필요가 없습니다.
다음 API 문서와 그 동작은 최종 버전에 도달할 때까지 변경될 수 있습니다.
clear()
| Property | Description |
|---|---|
| Return Value | None |
| Minimum Parameter Count | 0 |
| Maximum Parameter Count | 0 |
| Description | 이 내장 함수는 시각화 중인 커버리지를 지우고 활성 커버리지를 null로 설정합니다. |
| Aliases | None |
cwd( String : workingDirectory )
| Property | Description |
|---|---|
| Return Value | None |
| Minimum Parameter Count | 1 |
| Maximum Parameter Count | 1 |
| Description | 주어진 경로로 현재 작업 디렉터리를 설정합니다. cwd 이후에 절대 경로 없이 호출하는 모든 import는 활성 작업 디렉터리에서 커버리지 파일을 검색합니다. |
| Aliases | None |
diff( Variable : var1, var2, ..... varN )
| Property | Description |
|---|---|
| Return Value | Variable |
| Minimum Parameter Count | 2 |
| Maximum Parameter Count | Unlimited |
| Description | 주어진 가변 길이 Variables에 차집합 연산을 적용합니다. 결과 커버리지 변수를 반환합니다. |
| Aliases | None |
discard( Variable : var1, var2, ..... varN )
| Property | Description |
|---|---|
| Return Value | None |
| Minimum Parameter Count | 1 |
| Maximum Parameter Count | Unlimited |
| Description | 물리적 또는 논리적 변수를 삭제합니다. 먼저 커버리지 객체를 삭제한 후 변수 목록에서 변수 이름을 등록 해제합니다. 이 호출 이후에 주어진 모든 변수는 정의되지 않습니다. |
| Aliases | del |
distinct( Variable : var1, var2, ..... varN )
| Property | Description |
|---|---|
| Return Value | Variable |
| Minimum Parameter Count | 2 |
| Maximum Parameter Count | Unlimited |
| Description | 주어진 가변 길이 variables에 distinct (xor) 연산을 적용합니다. 결과 커버리지 변수를 반환합니다. |
| Aliases | xor |
goto( Integer : offset )