“25% 빨라진다”는 약속을
어떻게 읽어야 하는가
“PC 속도 25–40% 향상” 같은 약속이 무엇을 측정한 것인지, 그리고 왜 일반적인 사용자 PC에서는 그대로 재현되기 어려운지 — 측정 방법론의 관점에서 길게 풀어 씁니다.
성능 최적화 수치를 어떻게 읽어야 하는지, 그리고 우리가 무엇을 다르게 하는지에 대한 기록.
“PC 속도 25–40% 향상” 같은 약속이 무엇을 측정한 것인지, 그리고 왜 일반적인 사용자 PC에서는 그대로 재현되기 어려운지 — 측정 방법론의 관점에서 길게 풀어 씁니다.
Windows의 Multimedia Class Scheduler를 게임에 사용할 때 흔히 하는 오해 세 가지.
총량이 아니라 증가 속도를 추적할 때 보이는 것들. 그리고 false positive를 줄이는 두 가지 트릭.
"익명화"라는 단어 없이 텔레메트리를 끄는 방법, 그리고 그것을 외부에서 검증할 수 있게 만드는 방법.
Win11에서 도입된 QoS 클래스를 4시간 동안 측정한 결과, 그리고 노트북 종류별 효과 차이.
프로세스 메모리를 건드리지 않고 시스템 단에서만 작동하도록 한 부스터 설계.
"PC가 최대 40% 빨라집니다." — PC 최적화 도구를 검색해본 사람이라면 한 번쯤 본 문구입니다. 이 글은 그 약속이 무엇을 측정한 것이고, 왜 일반적인 사용자 PC에서는 그대로 재현되기 어려운지에 대한 노트입니다. 특정 도구를 비교 테스트한 결과를 담은 글이 아닙니다 — 우리는 그런 데이터를 공개적으로 검증할 입장에 있지 않습니다. 대신, 그런 주장이 무엇을 측정한 것인지, 그리고 왜 사용자 PC에서 거의 재현되지 않는지에 집중합니다.
대부분의 광고는 "벤치마크 점수 향상" 또는 "응답 속도 개선"이라는 모호한 지표를 사용합니다. 그러나 어떤 벤치마크인지, 어떤 부하 상태에서, 어떤 측정 도구로 측정했는지를 공개하지 않으면 그 숫자는 의미가 없습니다.
"측정값을 공개하지 않는 측정값은 측정값이 아닙니다."
현대 Windows 스케줄러는 이미 매우 잘 작동합니다. 일반적인 사용자 PC의 CPU·메모리·I/O 병목은 OS 자체가 아니라 백그라운드에서 돌고 있는 앱들 — 브라우저 다수 탭, 채팅 클라이언트, 백신 — 이 만들어냅니다. 그것들을 잠시 억제한다고 해도 합성 벤치마크는 거의 변하지 않습니다. 왜냐하면 그 벤치마크는 다른 앱이 거의 없는 상태에서 측정되기 때문입니다.
다시 말해, 벤치마크에서 25% 향상이 사실이라면 그것은 OS 자체나 하드웨어를 바꿨을 때만 가능합니다. 사용자 공간 도구로는 거의 불가능합니다.
OMEGA X의 모든 수치는 Win32 API의 직접 호출 결과입니다. GetProcessMemoryInfo, QueryProcessCycleTime, NtQuerySystemInformation. 우리는 그 결과를 그대로 표시합니다. 평균을 가공하지도, 가중치를 숨기지도 않습니다.
그리고 우리가 최적화하는 것은 합성 벤치마크 점수가 아니라 체감 반응성입니다. 백그라운드 부하가 클 때 포그라운드 앱이 얼마나 늦게 반응하는가. 게임 중에 끊김이 얼마나 자주 발생하는가. 마우스 입력이 얼마나 즉시 처리되는가. 이런 것들은 벤치마크 점수로 잘 잡히지 않지만 실제로 사용자가 느끼는 부분입니다.
정직성은 마케팅 카피가 아니라 코드 안에 있습니다.
* 이 글은 OMEGA X의 입장과 측정 철학에 대한 설명입니다. 특정 제품의 측정 결과를 보고하지 않으며, 비교 시험 결과를 주장하지 않습니다.
MMCSS(Multimedia Class Scheduler Service)는 Vista에서 도입된, 멀티미디어·게임 워크로드를 위한 스케줄러 보조 서비스입니다. "게이밍 부스터"라고 광고되는 도구의 상당수가 내부적으로는 이 API 한 줄을 호출하는 정도에서 끝납니다. 그래서 더더욱, 무엇이 실제로 일어나는지 알 필요가 있습니다.
스레드가 직접 AvSetMmThreadCharacteristicsW(L"Games", &idx)를 호출해 자신을 등록하면, MMCSS는 그 스레드에 다음을 부여합니다.
SystemResponsiveness 레지스트리 값)마지막 줄이 핵심입니다 — MMCSS는 "최대 성능"이 아니라 예측 가능한 지연을 만드는 도구입니다. 오디오 드롭아웃, 프레임 페이싱 흔들림을 줄이는 것이 본래 목적이고, FPS 평균을 올리는 도구가 아닙니다.
이건 자주 오해되는 부분입니다. AvSetMmThreadCharacteristicsW는 호출 스레드 자신만 등록합니다 — PID나 스레드 ID 인자가 없습니다. 다시 말해, 외부 도구가 "게임의 렌더 스레드를 MMCSS Games로 등록"하는 것은 API상 불가능합니다.
이 사실을 모르고 만든 "MMCSS 부스터"들은 실제로는 자기 자신의 헬퍼 스레드를 등록하고 끝납니다. 그 효과는 0이 아니지만, 광고와는 다릅니다.
우리도 같은 제약 안에 있습니다. optimizer.mmcss_register는 다음을 수행합니다.
def mmcss_register(self, fg_pid, fg_type):
task = "Games" if fg_type == "game" \
else "Pro Audio" if fg_type == "creative" \
else "Playback"
h = avrt.AvSetMmThreadCharacteristicsW(task, byref(idx)) # 자기 스레드
avrt.AvSetMmThreadPriority(h, 2) # HIGH (=2)
threading.Timer(1.5, lambda: avrt.AvRevertMmThreadCharacteristics(h)).start()
self.guard.record("mmcss", str(fg_pid), release) # 자동 복원 로그
요약 — OMEGA X의 헬퍼 스레드가 게임 활성 시점에 MMCSS Games로 자기를 등록하고, 1.5초 뒤 AvRevertMmThreadCharacteristics로 깔끔히 빠져나옵니다. 게임 자체의 스레드를 등록하는 것은 아닙니다 — 그건 API상 불가능합니다.
그래도 측정 가능한 효과가 있는 이유는, MMCSS Games 등록이 다음을 트리거하기 때문입니다.
SystemResponsiveness 기반 분배 정책이 활성화thread_burst, io_priority_boost, bg_throttle과 시너지다시 말해 MMCSS 한 줄이 마법을 일으키는 게 아니라, "이건 게임 시간이다"라는 신호를 OS에 명시적으로 알리는 효과입니다.
오해 1: 모든 게임 스레드를 등록하면 더 빨라진다. 잘못입니다. 등록은 스레드 자신만 할 수 있고, 등록 스레드가 늘어날수록 부스트 윈도우가 분할됩니다.
오해 2: Pro Audio가 게임에도 좋다. Pro Audio는 우선순위 26까지 부여되지만 그건 오디오 콜백의 데드라인(1–3ms)을 위한 것입니다. 게임 렌더 루프(16.67ms / 60fps)에는 과합니다. OMEGA X도 fg_type == "creative"(영상/오디오 편집)에서만 Pro Audio를 씁니다.
오해 3: SystemResponsiveness=0으로 낮추면 좋다. 이 레지스트리 값은 비등록 스레드에 보장되는 CPU 비율(기본 20%)을 제어합니다. 0으로 낮추면 GPU 드라이버·사운드 스택·네트워크 스택이 굶기 시작합니다. 결과는 보통 스터터 증가입니다. OMEGA X는 이 값을 절대 건드리지 않습니다.
MMCSS는 "켜는" 기능이 아닙니다. 자기 스레드만 등록할 수 있고, 그 효과는 시스템 분배 정책의 변경이라는 간접적인 신호입니다.
OMEGA X의 MMCSS 호출은 항상 1.5초 짜리 일회성 버스트입니다 (BURST_AFFINITY_MS = 1500 와 동일 윈도우). 이유 두 가지:
AvRevertMmThreadCharacteristics면 OS가 알아서 정리실제로 도움이 되는 조건은 좁습니다.
반대로 깨끗한 PC, 평균 FPS가 이미 모니터 주사율을 넘는 환경에서는 측정 가능한 차이를 만들지 못합니다. 그게 정직한 답입니다.
참고: Microsoft Docs — AvSetMmThreadCharacteristicsW, AvSetMmThreadPriority, HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\SystemResponsiveness. 본 글의 코드 발췌는 OMEGA X v1.0.x LatencyOptimizer.mmcss_register 실제 구현입니다.
메모리 누수 감지는 흔히 "총 사용량이 임계값을 넘으면 알림"이라는 방식으로 구현됩니다. 이 방식은 거의 항상 늦거나 거의 항상 잘못입니다. 4 GB 임계값은 16 GB PC에는 너무 낮고 64 GB PC에는 너무 낮습니다. 임계값은 누수의 신호가 아니라, 단순히 "메모리를 많이 쓰는 앱"의 신호일 뿐입니다.
누수의 정의는 단순합니다 — 해제되지 않는 할당의 누적. 그래서 시간에 대한 메모리 곡선의 기울기(1차 미분)가 0보다 일관되게 큰 경우, 누수일 가능성이 높습니다. 절대값은 무관합니다.
측정 자체는 가벼운 작업입니다. psutil.process_iter로 각 프로세스의 memory_info().rss를 일정 간격으로 샘플링하고 (OMEGA X는 전역 프로세스 캐시를 3초 TTL로 공유), 최근 N개 샘플의 선형 회귀 기울기를 구합니다.
slope = Σ(tᵢ · mᵢ) − N · t̄ · m̄
─────────────────────────────
Σ(tᵢ²) − N · t̄²
단위: MB/min, 최소 N=10 샘플 이상에서만 산출
이 단순한 방식은 false positive가 많습니다. 사용자가 사진을 100장 불러오면 working set이 가파르게 증가하지만, 그건 누수가 아닙니다. 두 가지로 걸러냅니다.
트릭 1: 두 윈도우 비교. 짧은 윈도우와 긴 윈도우 기울기를 동시에 봅니다. 진짜 누수는 두 윈도우에서 동시에 양수입니다. 사용자 액션은 짧은 윈도우에서만 양수, 긴 윈도우에서는 평탄해집니다.
트릭 2: idle 게이팅. 해당 프로세스의 CPU 사용률이 낮은 구간에서의 메모리 증가만 가중치를 둡니다. 사용자가 그 앱을 적극적으로 쓰고 있는 동안의 증가는 의도된 것일 확률이 높습니다. idle한데 메모리가 늘어나는 것이 누수의 본질입니다.
총량은 거짓말한다. 기울기는 거짓말하지 못한다.
UI에서 누수 알림은 세 단계로 분류됩니다 (i18n 키 그대로):
| 레벨 | i18n 키 | 표시 라벨 |
|---|---|---|
| 주의 | leak_severity_warn | "주의" |
| 경고 | leak_severity_danger | "경고" |
| 위험 | leak_severity_critical | "위험" |
그리고 증가량은 +{mb} MB / 지난 {min}분 포맷으로 표시됩니다 (leak_growth 키). 이 표시 형식은 총량이 아니라 증가율을 노출하기 위해 의도적으로 선택된 것입니다 — 사용자가 임계값이 절대값이 아님을 즉시 이해하게 만들기 위함입니다.
경고가 떠도 우리는 "메모리를 정리하세요"라고 하지 않습니다. 누수는 working set trim으로 해결되지 않습니다 — trim된 페이지는 곧 다시 page fault되어 돌아옵니다. 실제로 도움이 되는 건 그 앱을 재시작하는 것이고, 그것을 그대로 권합니다 (leak_action_restart).
Hard Core 모드에서는 알림에 회복 추정치를 함께 표시합니다 — 현재 working set에서 측정 시작 시점의 working set을 뺀 값. 이것은 "재시작하면 이만큼 회복될 가능성이 있다"는 추정이며, 마케팅 숫자가 아니라 그래프 위의 두 점을 빼는 산수입니다.
모든 프로세스를 매초 샘플링하면 그 자체로 CPU를 먹습니다. OMEGA X는 다음과 같이 비용을 낮춥니다.
PROC_CACHE(3초 TTL)를 다른 모든 측정과 공유 — psutil.process_iter가 walk를 한 번만 함그 결과, 누수 감지가 켜져 있어도 OMEGA X 자체의 CPU 점유는 idle 시 0.1% 내외에서 유지됩니다. "감지 도구 자체가 누수원이 되는" 아이러니를 피하기 위함입니다.
참고: psutil.Process.memory_info().rss, PROCESS_MEMORY_COUNTERS_EX의 WorkingSetSize. 본 글의 윈도우·임계값 세부 수치는 구현 디테일로 빌드별로 조정되며, 사용자 환경에 따라 자동 적응합니다. UI에 표시되는 라벨(주의 / 경고 / 위험)이 외부 계약 인터페이스이며, 내부 임계값은 그것에 맞춰 보정됩니다.
"개인정보를 수집하지 않습니다." 이 문장은 무의미합니다. 사용자는 그것을 검증할 수 없고, 회사는 정의를 마음대로 바꿀 수 있습니다. "익명화된 사용 통계"도 데이터 전송이고, "안정성 향상을 위한 진단 정보"도 데이터 전송입니다. 이 글은 우리가 텔레메트리·분석 SDK·광고 식별자를 미사용하는 것을 어떻게 코드 차원에서 드러내고 외부에서 검증 가능하게 만들었는지에 대한 기록입니다.
OMEGA X 바이너리가 외부와 통신하는 주요 경로는 업데이트 확인이며, 이 과정에서 오가는 것은 개인을 특정하지 않는 범위의 최소 정보입니다. 그 호출이 닿을 수 있는 도메인은 정확히 세 개로 코드에 박혀 있습니다.
# update_checker.py 의 _is_trusted_download_url(url) 로직
trusted = (
"https://github.com/sjw0328/Lite/",
"https://objects.githubusercontent.com/",
"https://api.github.com/repos/sjw0328/Lite/",
)
return any(url.startswith(p) for p in trusted)
다운로드 URL이 위 세 prefix 중 하나로 시작하지 않으면 요청 자체가 거부됩니다. GitHub Releases API가 응답하는 자산 URL은 실제로 objects.githubusercontent.com으로 redirect되므로, 그 호스트만 허용합니다. 그 외 도메인으로 가는 트래픽은 코드 경로 자체가 존재하지 않습니다.
정직하게 짚습니다 — 모든 HTTP 요청은 최소한의 메타데이터를 전송합니다. 무엇이 실제로 GitHub 서버에 도달하는지 정확히 명시합니다.
| 전송되는 것 | 값 |
|---|---|
| URL | /repos/sjw0328/Lite/releases |
User-Agent | OMEGA-X-Updater/{버전} — 현재 버전 포함 |
Accept | application/vnd.github+json |
| IP 주소 | 사용자 IP (TCP 연결의 자연스러운 결과) |
| 설치 ID / 텔레메트리 / 쿠키 | 없음 |
즉, GitHub은 이론적으로 "OMEGA X v1.0.2 사용자 중 모월모일 업데이트를 확인한 IP의 분포"를 알 수 있습니다. 우리는 이것을 보지 않으며, 받을 권한도 없습니다 — 그 데이터는 GitHub Inc. 의 서버 액세스 로그에 있을 뿐이고, 그쪽의 개인정보 처리방침을 따릅니다.
"수집하지 않는다"가 아니라 "전송 코드가 존재하지 않는다"가 검증 가능한 사실이다.
방법 1 — 정적 검증. 바이너리에서 모든 URL을 추출해 위 3개 호스트 외 도메인이 있는지 확인합니다.
strings OMEGA_X.exe | findstr /i "https://" # 결과(전부): # https://github.com/sjw0328/Lite/ # https://objects.githubusercontent.com/ # https://api.github.com/repos/sjw0328/Lite/releases # # 다른 호스트가 보이면 그것은 우리의 버그이거나 본 글의 거짓.
방법 2 — 런타임 검증. Windows 내장 pktmon으로 OMEGA X 프로세스의 송신 패킷을 캡처합니다. 업데이트 확인을 트리거하지 않는 일반 세션에서는 외향 트래픽이 관측되지 않는 것이 설계 의도이며, 업데이트 확인 시에는 위 3개 호스트로만 향합니다.
# 관리자 PowerShell pktmon filter add -p <OMEGA_X.exe의 PID> pktmon start --etw -m real-time # OMEGA X 일반 사용 (업데이트 확인은 누르지 않음) pktmon stop # > 외향 패킷 카운트가 0이어야 함
업데이트 시스템은 그 자체로 잠재적 추적 통로입니다. 우리는 다음과 같이 설계했습니다.
/releases 목록 GET 한 번 — "내가 v1.0.2인데 새 버전이 있냐"가 아니라 "최신이 뭐냐"만 묻습니다. 응답에서 비교는 클라이언트 측에서 수행%TEMP%\omega_update.log에만 기록 — 외부 전송 없음/SILENT 모드 — 사용자가 직접 빌드에서 가져온 .exe 만 실행 (PE header MZ 검증 + 최소 512KB 크기 검증)업데이트 확인 자체를 끄고 싶다면 설정에서 비활성화하면 됩니다. 그 후에는 has_update() 경로 자체가 실행되지 않습니다.
이 결정에는 비용이 있습니다.
%APPDATA%\OMEGA_X\error.log를 보내주지 않는 한 모릅니다크래시 로그는 opt-in입니다. error.log 파일은 PC 안에만 머무르며, 사용자가 직접 첨부하지 않는 한 절대 떠나지 않습니다. 그게 우리가 선택할 수 있는 가장 깨끗한 합의점이었습니다.
* 본 글의 코드 인용은 OMEGA X v1.0.x 실제 소스입니다. 설계 의도와 실제 동작이 다른 사례가 관찰되면 알려주세요 — 검토 후 수정하겠습니다. 본 글은 설계 설명이며, 특정 환경에서의 결과를 보장하지는 않습니다.
Windows 11 22H2(build 22621)부터 사용자 모드에서 안정적으로 호출 가능해진 EcoQoS는, 프로세스 단위로 "이 워크로드는 효율 코어(E-core)에서 낮은 주파수로 실행되어도 된다"는 힌트를 OS에 주는 API입니다. Microsoft 문서는 인상적인 그래프와 함께 발표되었지만 그건 합성 워크로드입니다. 이 글은 EcoQoS가 실제 무엇을 호출하는지, 언제 효과가 있고 언제 없는지에 대한 정리입니다.
EcoQoS는 별도 함수가 아닙니다 — SetProcessInformation의 ProcessPowerThrottling 정보 클래스(4)로 PROCESS_POWER_THROTTLING_STATE 구조체를 전달하는 호출입니다.
class PTS(Structure):
_fields_ = [("Version", c_ulong),
("ControlMask", c_ulong),
("StateMask", c_ulong)]
state = PTS()
state.Version = 1
state.ControlMask = 0x1 # PROCESS_POWER_THROTTLING_EXECUTION_SPEED
state.StateMask = 0x1 # 활성(=throttle ON)
SetProcessInformation(h, 4, byref(state), sizeof(state))
ControlMask=0x1은 "execution speed throttling 비트를 명시적으로 제어하겠다", StateMask=0x1은 "그 비트를 켜겠다"는 뜻입니다. ControlMask=0x1, StateMask=0x0이면 명시적으로 끄는 것이고, 두 마스크 모두 0이면 기본값으로 되돌립니다.
EcoQoS가 켜진 프로세스에 대해 Windows 스케줄러는 다음을 시도합니다.
이 셋 중 가장 큰 절감 효과는 첫 번째 — E-core 배치 — 에서 옵니다. 그리고 그것은 E-core가 존재하는 CPU에서만 의미가 있습니다. 동질 코어 CPU(예: 11세대 이전 Intel, 7000 시리즈 이전 AMD 일부)에서는 EcoQoS의 효과가 주파수 캡 정도로 줄어듭니다.
EcoQoS는 마법이 아닙니다. 빅·리틀 코어가 있는 CPU에서 큰 효과를 보고, 아니면 약합니다. 그게 전부입니다.
EcoQoS를 잘못 적용하면 부작용이 큽니다. 백신 실시간 검사에 걸면 파일 열림이 느려지고, 네트워크 드라이버에 걸면 게임 핑이 튑니다. 오디오 스택에 걸면 1ms 단위의 드롭아웃("지지직")이 발생합니다.
OMEGA X는 명시적인 exclude-list 방식을 씁니다 — 다음 두 필터를 통과해야만 EcoQoS 대상이 됩니다.
SYSTEM_WHITELIST = { # 절대 건드리지 않음
"system", "svchost.exe", "csrss.exe", "wininit.exe",
"services.exe", "winlogon.exe", "lsass.exe",
"msmpeng.exe", # Windows Defender
"mssense.exe", # MS Defender for Endpoint
"audiodg.exe", "dwm.exe", ...
}
SAFE_KEYWORDS = ( # 이름에 이 키워드가 들어가면 제외
"nvidia", "amd", "intel", # GPU/칩셋 드라이버
"antivirus", "defender", # 보안 솔루션
"audio", "asio", "voicemeeter", # 오디오 스택
)
추가 조건:
pid != fg_pid # 포그라운드는 제외
cpu_percent >= 0.5 # 일하지 않는 프로세스는 의미 없음
최대 25개까지만 적용 (Hard Core)
이 방식의 장단점은 분명합니다 — 장점: 새로운 사용자 앱을 화이트리스트에 추가할 필요 없이 자동으로 잡힙니다. 단점: 위 SAFE_KEYWORDS에 들어가지 않은 새로운 보안·오디오 솔루션은 잡힐 수 있습니다. 해당 케이스가 보고되면 키워드를 추가합니다.
EcoQoS의 효과는 CPU 아키텍처에 강하게 의존합니다.
| 아키텍처 | 예시 | 예상 효과 폭 |
|---|---|---|
| 이질 코어 (P+E) | Intel 12세대 이후, Snapdragon X | 큼 — E-core 배치 효과 |
| 이질 코어 (P+E) | Ryzen 9000 X3D 등 일부 모델 | 중간 |
| 동질 코어 | Ryzen 7000U, Intel 11세대 이전 | 작음 — 주파수 캡만 |
구체적 % 수치는 작업 종류와 배터리 화학에 따라 크게 달라지므로 단정하지 않습니다. 같은 노트북이라도 사무 작업과 동영상 재생의 결과가 다릅니다. 벤더가 "X% 배터리 향상"이라고 단언한다면, 그건 합성 환경의 숫자입니다.
데스크톱에는 배터리가 없으니 전력 절감 자체의 의미는 약합니다. 다만 EcoQoS는 부수 효과로 발열·팬 소음을 줄입니다. 백그라운드의 무거운 클라우드 동기화, IDE indexing 같은 작업이 E-core로 옮겨가면 P-core가 idle을 유지하므로 패키지 평균 온도가 떨어집니다.
조용한 PC를 원한다면, 노트북에서만 의미가 있는 게 아닙니다.
예. 다음 호출로 원상 복구됩니다.
state.ControlMask = 0x0 state.StateMask = 0x0 SetProcessInformation(h, 4, byref(state), sizeof(state))
또한 EcoQoS 상태는 프로세스 종료 시 자동 해제됩니다. 즉, OMEGA X가 EcoQoS를 적용한 프로세스를 종료시키지 않는 한, 우리 도구를 종료해도 그 프로세스가 재시작될 때까지는 EcoQoS가 유지되었다가 다음 실행 시 깨끗한 기본값으로 돌아옵니다. 시스템에 영구 변경이 남지 않습니다.
참고: Microsoft Docs — SetProcessInformation, PROCESS_INFORMATION_CLASS의 ProcessPowerThrottling(=4), PROCESS_POWER_THROTTLING_STATE. 본 글의 모든 코드 발췌는 OMEGA X v1.0.x LatencyOptimizer.apply_ecoqos 와 CoreMode._apply_ecoqos_bulk 의 실제 구현입니다.
게임 부스터가 안티치트에 차단되는 가장 흔한 이유는 게임 프로세스의 메모리를 읽거나 쓰는 것입니다. ReadProcessMemory, WriteProcessMemory, VirtualAllocEx + CreateRemoteThread — 치트가 쓰는 도구와 부스터가 쓰는 도구가 같으면, 커널 안티치트는 둘을 구분하지 않습니다.
OMEGA X의 설계 원칙은 단 하나입니다 — 핸들은 열되, 메모리는 만지지 않는다. 이 글은 그 경계가 코드 어디에 있는지, 그리고 우리가 정직하게 인정해야 할 한계가 무엇인지에 대한 노트입니다.
주요 커널 모드 안티치트가 보호 대상 프로세스에 대해 의심하는 행위는 대략 다음과 같이 정리됩니다.
ReadProcessMemory / WriteProcessMemory — 메모리 R/WNtReadVirtualMemory / NtWriteVirtualMemory — 같은 동작의 NT 진입점VirtualAllocEx + CreateRemoteThread — 코드 인젝션NtMapViewOfSection 또는 드라이버를 이용한 메모리 매핑SetWindowsHookEx, AppInit_DLLs, manual map)핸들 자체(OpenProcess)는 일반적으로 그 자체로 차단 사유가 아닙니다 — 작업 관리자, perfmon, 백신 모두 게임 프로세스 핸들을 엽니다. 차단 트리거는 거의 항상 그 핸들로 무엇을 했는가입니다.
코드에 실제로 들어 있는 외부 API 호출은 다음이 전부입니다.
| API | 호출 위치 | 대상 |
|---|---|---|
OpenProcess(PROCESS_ALL_ACCESS) | io_priority_boost, idle_cleanup | 포그라운드 PID(게임 포함) + BG |
OpenThread(THREAD_SET_INFORMATION | QUERY) | thread_burst, affinity_hint | 포그라운드 스레드 |
SetThreadPriority(h, THREAD_PRIORITY_HIGHEST) | 버스트 부스트 | 포그라운드 스레드 |
NtSetInformationProcess(h, 33, &v) | I/O priority | FG=High, BG=Low |
SetProcessInformation(h, 4, &PTS) | EcoQoS | BG only (FG 제외) |
SetThreadIdealProcessor(h, 0) | P-core 힌트 | 포그라운드 스레드 |
EmptyWorkingSet(h) | working set trim | BG only (whitelist 필터) |
AvSetMmThreadCharacteristicsW("Games") | MMCSS 등록 | 자기(헬퍼) 스레드 |
중요한 점 — 이 목록에 ReadProcessMemory, WriteProcessMemory, CreateRemoteThread, VirtualAllocEx는 존재하지 않습니다. 바이너리에서 strings나 IDA로 import 테이블을 봐도 동일하게 확인 가능합니다.
이 부분은 명확히 짚고 갑니다. I/O priority를 조정하려면 게임 프로세스의 핸들이 필요합니다. io_priority_boost(fg_pid)는 포그라운드가 게임일 때 게임 PID로 OpenProcess(PROCESS_ALL_ACCESS)를 호출합니다.
그 핸들로 우리가 한 일은 단 두 가지입니다:
NtSetInformationProcess(h, IoPriority=33, &value) — I/O 우선순위 클래스를 변경CloseHandle(h) — 즉시 닫음그리고 1.5초 후 자동으로 NORMAL로 복원됩니다 (threading.Timer(BURST_IO_MS/1000.0, restore)). 핸들의 수명은 보통 마이크로초 단위입니다.
핸들을 여는 것이 아니라 핸들로 무엇을 하느냐가 문제다.
왜 PROCESS_ALL_ACCESS를 요청하느냐 — 그건 부끄럽지만 사실 Windows의 API 설계 한계입니다. NtSetInformationProcess가 요구하는 정확한 최소 권한은 문서화되어 있지 않고, 실제로는 PROCESS_SET_INFORMATION만으로도 동작할 가능성이 높지만, 모든 빌드에서 안정 동작하는 것이 우선이라 더 넓은 권한을 요청합니다. 향후 빌드에서 최소 권한으로 축소할 예정입니다.
한편, OMEGA X가 절대 건드리지 않는 프로세스가 코드에 명시되어 있습니다 (SYSTEM_WHITELIST, SAFE_KEYWORDS).
SYSTEM_WHITELIST = {
"system", "svchost.exe", "wininit.exe", "services.exe",
"csrss.exe", "winlogon.exe", "lsass.exe", "smss.exe",
"msmpeng.exe", # Windows Defender
"mssense.exe", # MS Defender for Endpoint
...
}
SAFE_KEYWORDS = (
"nvidia", "amd", "intel",
"antivirus", "defender",
"audiodg", "asio", "audio", # 오디오 스택
...
)
안티치트 드라이버는 보통 자기 자신을 보호된 프로세스로 로드하므로 처음부터 핸들 자체가 거부됩니다 — 명시 화이트리스트가 없어도 안전합니다. 그러나 보안 솔루션 / 오디오 스택 / GPU 드라이버 프로세스는 명시 차단이 필요해 위 목록에 있습니다.
이 부분은 분명히 짚고 갑니다. OMEGA X가 게임 프로세스의 메모리를 읽거나 쓰지 않는 것은 설계상 사실이지만, 안티치트 솔루션이 어떤 행위를 어떻게 평가하는지는 전적으로 각 게임사·안티치트 제공자의 비공개 정책에 달려 있고, 버전·시점·환경에 따라 언제든 달라질 수 있습니다. 따라서 우리는 어떤 안티치트와의 호환성도, 계정이 안전하다는 것도, 차단이 발생하지 않는다는 것도 보장하지 않습니다. 계정 제재를 포함한 모든 위험은 사용자 본인이 부담합니다. 믿어달라고 말하는 대신, 아래 방법으로 설계 의도를 직접 검증하시길 권합니다.
믿어달라고 말하기보다 검증 방법을 알려드리는 쪽이 정직합니다.
# 1. import 테이블에 위험 API가 없는지 확인 dumpbin /imports OMEGA_X.exe | findstr /i "ReadProcessMemory WriteProcessMemory CreateRemoteThread VirtualAllocEx" # 2. 실행 중 호출 트레이스 (관리자 PowerShell) logman create trace omega -p "Microsoft-Windows-Kernel-Process" -o omega.etl # 게임 실행 후 OMEGA X 가동 logman stop omega # omega.etl 에서 우리 PID의 RPM/WPM 호출 횟수 = 0 이어야 함
* OMEGA X v1.0.x 기준. 어떤 안티치트도 OMEGA X와 공식 호환을 인증하지 않으며, 본 글은 그러한 인증이나 계정 안전·차단 비발생을 주장하지 않습니다. 사용에 따른 계정 제재 등 모든 위험은 사용자 본인이 부담합니다. 검증은 사용자가 직접 수행 가능하며, 위 방법으로 설계 의도와 다른 동작이 관측되면 알려주세요.