디버거가 실행환경에 남기는 흔적을 검사해 디버거 여부를 탐지하는 기법
리눅스 커널이 관리하는 프로세스 및 시스템 정보를 파일 형태로 제공하는 가상 파일 시스템

프로세스 상태, 메모리 매핑, 파일 디스크립터등
/proc/<PID>/status
프로세스 상태를 저장하는 파일


/proc에서 프로세스 이름을 확인하고 debugger가 붙어있는지의 여부를 판단한다


/proc에서 프로세스 TracerPid의 수상한 변화로 디버거를 탐지합니다

함수 반환값을 조작해 이름을 확인하지 못하게 합니다

pid를 수동으로 변경해버립니다
디버깅 과정에서만 발생하는 동적인 변화와 부작용을 통해 판별하는 기법

인터럽트(사용자 입력등)이 없다는 가정 하에
디버깅시간이 프로그램 실행시간보다 오래걸린다 -> 수상함

디버깅 스크립트 사용해서 시간단축
breakpoint를 만났을때 프로세스에 신호를 전달
break *0x10 => 0x10 int3
break는 코드를 덮어써서 중단하는 것이므로 .text섹션 변조를 확인해 탐지한다

pwndbg > signal SIGTRAP
핸들러가 처리한 SIGTRAP 신호를 다시 디버거에게 전달 -> 신호를 받고 계속 실행한다

일단 main으로 가보자

일단 위의 sub_401260은 debugging을 하고 있는지 확인하는 것 같다

term_proc 부터 sub_401260까지 무결성 검사를 진행한다
v2 = 0x1337133713371337LL * a2[1];
v3 = a2[3];
v4 = *a2;
v418 = __readfsqword(0x28u);
v6 = ((unsigned __int64)a2[2] >> 49) ^ v2;
v7 = v6 + 0x2D00771F0DE31B80LL;
v8 = v6
- 0x3016B66B1261B5BLL
+ ((v6 + 0x2D00771F0DE31B80LL - v3)
^ ((v3 | 0xA4D30FDFDD6C0E2CLL) + ((v6 + 0x2D00771F0DE31B80LL) & 0xA4D30FDFDD6C0E2CLL)));
v9 = syscall(257, 4294967196LL, "/proc/self/status", 0x80000, 0);
if ( v9 >= 0 )
{
v411 = v9;
v400 = syscall(0, (unsigned int)v9, &v417[11], 4095);
syscall(3, v411);
if ( v400 > 0 )
{
v417[v400 + 11] = 0;
strcpy(v417, "TracerPid:");
if ( v400 > 10 )
{
v10 = &v417[11];
v11 = 0;
while ( 2 )
{
v12 = 0;
while ( v10[v12] == v417[v12] )
{
if ( ++v12 == 10 )
{
v13 = v11 + 10;
v14 = v417[v13 + 11];
v15 = &v417[v13 + 11];
if ( v14 == 32 || v14 == 9 )
{
do
{
do
v16 = *++v15;
while ( v16 == 32 );
}
while ( v16 == 9 );
}
else
{
v16 = *v15;
}
if ( (unsigned __int8)(v16 - 48) <= 9u )
{
v17 = 0;
do
{
++v15;
v17 = (char)(v16 - 48) + 10 * v17;
v16 = *v15;
}
while ( (unsigned __int8)(*v15 - 48) <= 9u );
if ( v17 )
v7 = v6 - 0x3AF14F617E15B71ALL;
}
goto LABEL_17;
}
}
++v11;
++v10;
if ( v11 != v400 - 10 )
continue;
break;
}
}
}
}
sub_401380에 break들이 있는 것을 볼 수 있다

입력을 받는다

64자리 16진수인지 확인하고 16진수로 저장
변환된 결과는 v2에 저장되고
v4배열과 비교해 올바른 입력인지 검증
검증단계에서 v4배열값을 확인하고 16진수 문자열로 바꾼다면?
플래그 get

main주소에 브레이크를 걸고 실행해 무결성검사 전까지 간다
무결성 검사를 하는 주소들은 건드리지말고 건너뛴다

프로세스id를 확인하고
cat /proc/<pid>/status > fake_status
sed -i 's/TracerPid:\t[0-9]*/TracerPid:\t0/' fake_status
sudo mount --bind fake_status /proc/<pid>/status

덮어써서 우회해준다

sub401380이 끝나는 곳에 하드웨어 브레이크포인트를 걸어준다 아무 64글자 입력

마지막 break 0x40439까지 signal SIGTRAP으로 가준다

그후 continue로 빠져나오고

v4부터 시작하는 64개의 16진수를 확인하고 문자로 바꿔준다
