[2024-02-23] 내가 만든 실행 파일이 바이러스로 오탐지 될 때
서론
지난번에 Pyinstaller로 exe를 만들고 사설 전자 서명을 하면 된다고 했던 것 같다. 그런데 어쩐지 해결이 잘 안되고, 무슨 짓을 해도 바이러스로 오탐지 되고 있다.
이건 좀 많이 곤란하다. 아무리 토이프로젝트라고는 하지만 공용으로 배포해야 하는데 실행조차 못하고 사라져간 프로그램들을 생각하면 눈물이 난다. 어떻게든 이걸 해결해야 한다.
본론
사실 가장 간단한 방법은 Windows Defender에 예외를 설정하는 거다. 하지만 사용자는 그리 적극적인 존재가 아니다. 뭔가 안된다 싶으면 그냥 지워버리는 것이 사람 심리다. 따라서 유저 경험을 최대화하기 위해서라도 나는 이것을 코드 수준에서 해결해야 한다.
그래서 생각한 것이, 실행 파일을 감싸는 실행 파일을 만들면 되지 않을까? 였다. 어차피 이미 만들어진 파일을 수정하는 것은 사실상 전부 갈아 엎으라는 소리이기도 하니, 차라리 일종의 런처를 만들어 우회하면 해결될 듯 싶었다.
그런데 파이썬 실행 파일을 위한 파이썬 실행 파일을 만들면 결국 똑같은 짓이다. 결국 파이썬 파일을 exe로 빌드하면 똑같이 오탐지가 날게 분명하다. 그러니 가벼우면서도 어떻게든 해결할 수 있을 것 같은 c++을 이용하기로 했다.
방법은 간단하다. c++파일에서 파이썬으로 생성한 파일을 실행하면 된다. 단, 파이썬 파일이 작업 관리자 환경에서 실행되어야 하니 c++도 작업 관리자 권한을 요구하도록 빌드해야 한다. 그래서 성공했냐 하면 당연히 실패했다.
int main()
{
std::wstring processName = L"UmaKey.exe";
ShellExecute(NULL, NULL, processName.c_str(), NULL, NULL, SW_HIDE);
}
대충 이런 식으로 하면 되지 않을까 했지만 c++도 여전히 바이러스로 숙청당했다. 그래서 다음으로 생각한 것이, 차라리 그냥 코드로 Window defender에 예외를 추가하면 되지 않을까? 였다. 다시 한 번 말하지만, 제일 좋은 방법은 돈주고 전자 서명 사고, 윈도우 디펜더에 오탐지 보고를 하는 것이다. 나는 야매 방법을 시도하고 있는 거다.
아무튼 그래서 어떻게 됐냐 하면 또 실패했다.
int main()
{
std::wstring processName = L"UmaKey.exe";
std::wstring powershellCmd = L"Add-MpPreference -ExclusionPath \"" + fs::current_path().wstring() + L"\"";
ShellExecute(NULL, NULL, L"powershell.exe", powershellCmd.c_str(), NULL, SW_HIDE);
ShellExecute(NULL, NULL, processName.c_str(), NULL, NULL, SW_HIDE);
}
이번엔 이론상 완벽했는데… 아무래도 실행하기 전에 무언가 검사를 하는 듯 싶다. 그렇게 한참을 해매다가 코드로 다른 프로그램을 실행하면 바이러스로 탐지된다는 사실을 알았다. 어째서다…
물론 이해는 한다만 나같은 사람은 어떡하란 소린지. 세상 참 각박하다. 그래서 또 열심히 머리를 굴렸고, 정적인 파일로는 도저히 안되겠다는 결론을 내렸다. 무언가 동적 할당을 하든, 조건을 걸어서 우회하든 해야한다는 결론이었다.
그래서 위 코드에서 문자열을 전부 동적 할당으로 바꿔 봤지만 어림도 없지. 또 실패다. 그렇다면 이제 조건인데, 과연 무엇을 조건으로 할 지가 관건이었다. 항상 참인 조건이지만, 또 프로그램이 실행되기 전 검사할 때는 걸리지 않는…
그 어려운 걸 내가 해냈다. 코드는 다음과 같다.
bool IsCurrentUserAdmin() {
BOOL isAdmin = FALSE;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup)) {
return false;
}
if (!CheckTokenMembership(NULL, AdministratorsGroup, &isAdmin)) {
isAdmin = FALSE;
}
FreeSid(AdministratorsGroup);
return isAdmin == TRUE;
}
int main() {
std::wstring processName = L"UmaKey.exe";
std::wstring powershellCmd = L"Add-MpPreference -ExclusionPath \"" + fs::current_path().wstring() + L"\"";
ShellExecute(NULL, NULL, L"powershell.exe", powershellCmd.c_str(), NULL, SW_HIDE);
if (IsCurrentUserAdmin()) {
ShellExecute(NULL, NULL, processName.c_str(), NULL, NULL, SW_HIDE);
}
else {
char a;
std::cin >> a;
}
return 0;
}
보이는가? 현재 환경이 관리자 권한인지 아닌지로 구분해 놨다. 그리고 이것은 정상적으로 작동한다. 이 멍청한 컴퓨터 자식. 내가 이겼다. 이러면 예외로 등록됨과 동시에 문제 없이 파일이 실행된다. 단 관리자 권한으로 실행하며, 사설 전자 서명을 했다는 가정이다. 안하면 어떻게 되냐 하면, 안해봐서 모른다. 지금도 되는데 굳이 다른걸 시도할 필요가 있을까?
이렇게 해서 나는 프로그램을 실행하는 일종의 런처를 만들었고, 성공적으로 바이러스 오탐지에서 벗어날 수 있었다. Pyinstaller든, nuitka든, 심지어는 컴파일된 c++ 파일이든 바이러스로 오탐지 된다면, 이와 같은 방법으로 해결할 수 있다.
임시 방편임을 명심하자. 별로 좋은 방법은 아니다. 최고로 좋은 건 돈 쓰는 거다.