보안설정방법
해당 프로세스가 디버거에 의해 제어 받고 있는지 확인하고 탐지, 종료하는 루틴을 삽입하여 해당 프로세스를 강제 종료시켜야 함(한가지 방식 적용이 아닌 아래의 방식을 모두 적용하여 프로세스 실행 중 주기적인 검증 수행 필요)
<Android>
소스 구현 영역에 따라 SDK(Java)와 NDK(C, Natice)로 구현 가능함.
<참고. SDK Java 소스 구현 방안>
[구현 방안 1 : 디버그 프로세스 탐지]
static int detect_isDebuggerPresent(){
if(Debug.isDebuggerConnected())
return 1;
else return 0;
}
[구현 방안 2 : 디버깅 시 브레이크 포인트가 걸리는 시간 측정]
static boolean detect_threadCpuTimeNanos () {
long start = Debug.threadCpuTimeNanos ();
for(int i = 0; i <1000000; ++i )
continue;
long stop = Debug.threadCpuTimeNanos();
if(stop - start < 10000000)
return false ;
else
return true ;
}
<참고. NDK C 소스 구현 방안>
구현 방안 1 : 디버그 프로세스 탐지]
JNIEXPORT jboolean JNICALL Java_poc_c_detectdebuggerConnected (JNIEnv* env,jobject dontuse)
if(gDvm.debuggerConnected || gDvm.debuggerActive){
return JNI_TRUE ;
return JNI_FALSE ;
}
[구현 방안 2 : process status 파일 확인]
#ifndef JNI_ANDROID_ANTI_DEBUG_H_
#define JNI_ANDROID_ANTI_DEBUG_H_
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* JNI_ANDROID_ANTI_DEBUG_H_ */
#include <android/log.h>
#include <jni.h>
#include <string>
#include <sys/ptrace.h>
#include <unistd.h>
#include <stdlib.h>
#include <chrono>
#include <thread>
void be_attached_check()
{
try
{
const int bufsize = 1024;
char filename[bufsize];
char line[bufsize];
int pid = getpid();
sprintf(filename, "/proc/%d/status", pid);
FILE* fd = fopen(filename, "r");
if (fd != nullptr)
{
while (fgets(line, bufsize, fd))
{
if (strncmp(line, "TracerPid", 9) == 0)
{
int statue = atoi(&line[10]);
LOGD("%s", line);
if (statue != 0)
{
LOGD("be attached !! kill %d", pid);
fclose(fd);
int ret = kill(pid, SIGKILL);
}
break;
}
}
fclose(fd);
} else
{
LOGD("open %s fail...", filename);
}
} catch (...)
{
}
}
void thread_task(int n)
{
while (true)
{
LOGD("start be_attached_check...");
be_attached_check();
std::this_thread::sleep_for(std::chrono::seconds(n));
}
}
void anti_debug()
{
LOGD("call anti_debug ......");
auto checkThread = std::thread(thread_task, 1);
checkThread.detach();
}
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
anti_debug();
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
{
return -1;
}
return JNI_VERSION_1_6;
}
[구현 방안 3 : ptrace 선점을 통한 디버거process attach 방지]
#include <jni.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <pthread.h>
static int child_pid;
void * monitor_pid(void *pVoid) {
int status;
waitpid(child_pid, &status, 0);
/* Child status should never change. */
_exit(0); // Commit seppuku
}
void anti_debug() {
child_pid = fork();
if (child_pid == 0)
{
int ppid = getppid();
int status;
if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0)
{
waitpid(ppid, &status, 0);
ptrace(PTRACE_CONT, ppid, NULL, NULL);
while (waitpid(ppid, &status, 0)) {
if (WIFSTOPPED(status)) {
ptrace(PTRACE_CONT, ppid, NULL, NULL);
} else {
// Process has exited
_exit(0);
}
}
}
} else {
pthread_t t;
/* Start the monitoring thread */
pthread_create(&t, NULL, monitor_pid, (void *)NULL);
}
}
JNIEXPORT void JNICALL
Java_sg_vantagepoint_antidebug_MainActivity_antidebug(JNIEnv *env, jobject instance) {
anti_debug();
}
<iOS>
아래는 프로그램이 디버거로 제어를 받고 있는지 탐지, 종료하는 예제코드임.
<참고. 구현 방안>
[구현 방안 1]
// main.m
// ProtectionSample
#import <Cocoa/Cocoa.h>
#include <sys/ptrace.h>
int main(int argc, char *argv[])
{
//Build settings -> Other C Flags: -DDEBUG
#ifdef DEBUG
//do nothing
#else
ptrace(PT_DENY_ATTACH, 0, 0, 0);
#endif
return NSApplicationMain(argc, (const char **) argv);
[구현 방안 2]
#import <dlfcn.h>
#import <sys/types.h>
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif // !defined(PT_DENY_ATTACH)
void disable_gdb() {
void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace");
ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
dlclose(handle);
}
[방안 3 : 파일 변경 확인 또는 디버거에 의한 실행 확인 방법]
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
NSString* path = [NSString stringWithFormat:@"%@/Info.plist", bundlePath];
NSString* path2 = [NSString stringWithFormat:@"%@/AppName", bundlePath];
NSDate* infoModifiedDate = [[[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES] fileModificationDate];
NSDate* infoModifiedDate2 = [[[NSFileManager defaultManager] fileAttributesAtPath:path2 traverseLink:YES] fileModificationDate];
NSDate* pkgInfoModifiedDate = [[[NSFileManager defaultManager] fileAttributesAtPath:[[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:@"PkgInfo"] traverseLink:YES] fileModificationDate];
if([infoModifiedDate timeIntervalSinceReferenceDate] > [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) {
//파일 변경
}
if([infoModifiedDate2 timeIntervalSinceReferenceDate] > [pkgInfoModifiedDate timeIntervalSinceReferenceDate]) {
//파일변경
}
'모바일' 카테고리의 다른 글
android jadx tool (0) | 2021.12.11 |
---|---|
dex2jar 에러 경로 참고 (0) | 2021.12.11 |
LLDB 디버깅 명령어 건 (0) | 2021.08.31 |
딥링크란?? (0) | 2021.08.03 |
3utools GPS 변경 건 (0) | 2021.07.02 |