TECH 으로 돌아가기
TECH HACKER NEWS 오늘 9분 읽기 27 READS

로컬에서 만든 AI 이미지에도 눈에 안 보이는 워터마크가 박힌다: MS 그림판·사진 분석

로컬에서 만든 AI 이미지에도 눈에 안 보이는 워터마크가 박힌다: MS 그림판·사진 분석
SOURCE IMAGE · HACKER NEWS

윈도우 그림판(Paint)과 사진(Photos)에 들어간 AI 이미지 생성 기능을 리버스 엔지니어링한 분석이 공개됐다. 결론부터 말하면, 이 두 앱은 사용자가 만든 AI 이미지의 픽셀 안에 사람 눈에 보이지 않는 워터마크를 심으며, 그 워터마크의 식별자는 서버가 발급한 GUID다. 심지어 기기 안에서 이미지를 생성하는 '로컬' 경로에서도 이 GUID는 네트워크 요청을 통해 마이크로소프트 서버로부터 받아온다. '로컬 생성'이 곧 '완전한 오프라인 처리'를 의미하지 않는다는 점이 이 분석의 핵심이다.

분석자는 처음에 그림판이 단순히 원격 API를 호출해 이미지를 만들 것이라 예상했지만, 실제로는 윈도우가 Copilot의 일부로 로컬 모델을 함께 배포하고 있음을 확인했다. 그림판 폴더에는 .onnxe 확장자를 가진 모델 파일 네 개가 있었고, 이는 'Microsoft_2023' 같은 키로 XOR 복호화하면 정상적인 ONNX 파일이 되는 구조였다. 복호화 후에는 표준 ONNX 검증 함수가 정상 동작했다. 여기서 눈에 띈 것이 1.67MB에 달하는 Watermarker.dll이었다. 오른쪽 아래에 Copilot 로고를 넣는 눈에 보이는 워터마크만으로는 이 정도 크기가 설명되지 않았고, 이것이 분석의 실마리가 됐다.

픽셀에 새겨지는 144비트

보이는 워터마크는 AddPerceptibleWatermark 함수가 담당하지만, 그와 별개로 WmkWriteWatermark라는 함수가 존재했다. 이 함수는 로컬 스테이블 디퓨전 생성이 끝난 뒤 호출되며, 입력으로 정확히 16바이트짜리 페이로드를 받는다. 상위 호출부의 시그니처를 따라가 보니 이 16바이트는 winrt::guid, 즉 GUID였다. 래퍼는 이 GUID를 포함해 18바이트(144비트) 메시지를 구성하고, 인코더는 이미지 크기를 8의 배수로 내림한 뒤 144개의 비트를 각각 최소 세 번 이상 배치한다. 3×5 행렬 연산과 행렬 분해 루틴, 24.0·0.25·0.5·0.2 같은 상수를 쓰는 방식은 콘텐츠 적응형 블록 도메인 SVD 계열 워터마크로 보인다. 실제로 512×512 테스트 이미지에서는 26만여 픽셀 중 19만 개 이상이 변경됐다.

로컬 생성인데 왜 서버 GUID인가

페이로드의 출처를 역추적한 결과, GUID는 이미지 생성 직전에 보내는 네트워크 요청에서 나온다. 그림판은 로컬 모델을 돌리기 전에 프롬프트와 스타일을 서버의 조정(moderation) 엔드포인트로 보내고, 서버는 promptGenerationId와 watermarkId 두 개의 GUID를 돌려준다. 이 중 watermarkId가 픽셀에 박히는 값이다. 분석자는 그림판의 인증 세션을 재사용해 실제 응답을 확인했는데, '파란 모자를 쓴 웃는 사람의 초상'이라는 프롬프트에서는 containsHumanReference 필드가 true로 돌아왔다. 즉 서버는 프롬프트가 사람을 지칭하는지까지 분류해 저장한다. 또한 그림판은 직전 생성의 ID를 다음 요청에 lastPromptGenerationId로 함께 보내, 연속된 요청들을 서버가 명시적으로 연결할 수 있게 한다.

워터마크가 픽셀 층의 신호라면, 파일 층에는 C2PA 콘텐츠 자격증명이 붙는다. 저장된 PNG의 IHDR 청크 바로 뒤에는 약 1만9천 바이트의 caBX 청크가 있었고, 그 안의 서명된 C2PA 매니페스트에는 c2pa.soft-binding.value가 담겨 있었다. 결정적으로, 서버가 발급한 watermarkId와 픽셀에 심긴 식별자, 그리고 C2PA의 소프트 바인딩 값이 생성마다 동일한 하나의 값이었다. C2PA에서 소프트 바인딩은 파일 단위 매니페스트가 제거되더라도 콘텐츠를 원래 출처 기록과 다시 연결할 수 있게 하는 장치다. 마이크로소프트는 이 어설션을 암호학적으로 서명했고, 여기에 'Microsoft InvisMark'라는 이름을 명시했다.

이 구조를 이해하면 그림판이 두 개의 서로 다른 생성 경로를 갖는 이유가 드러난다. Image Creator 기능은 Azure OpenAI ImageGen을 쓰며, 생성·워터마킹·프로버넌스 패키징이 모두 클라우드에서 끝난 완성 이미지를 받아올 수 있다. 반면 Cocreator는 지원되는 Copilot+ PC의 NPU에서 스테이블 디퓨전 추론이 실제로 기기 안에서 돌아간다. 다만 안전성 검사는 여전히 Azure 온라인 서비스가 수행하므로 마이크로소프트 계정과 인터넷 연결이 요구된다. 클라우드 생성기는 반환 전에 스스로 워터마크를 넣을 수 있지만 로컬 생성기는 그럴 수 없기 때문에, 그림판이 직접 픽셀을 고칠 로컬 워터마크 구현이 필요한 것이다. 그림판이 WmkWriteWatermark 실패를 워터마크 없는 이미지 반환이 아니라 생성 전체의 실패로 처리하는 것도 같은 맥락이다. 다만 같은 이름의 DLL을 가진 사진 앱은 워터마크 인코더가 오류를 내도 로그만 남기고 이미지를 반환하는 것으로 보여, 두 앱의 실패 동작이 다르다.

실무자가 눈여겨볼 지점과 한계

저장 경로 설계에서도 프로버넌스 우선 원칙이 드러난다. Image Creator 창에서 직접 저장할 때 제공되는 포맷은 PNG 하나뿐이고, 캔버스에 적용한 뒤에도 PNG·JPEG·GIF와 자체 .paint 포맷만 남으며 그림판의 고전 포맷인 BMP는 빠진다. 이는 C2PA가 매니페스트를 담을 수 있는 포맷과 정확히 일치한다. BMP는 외부 매니페스트 없이는 임의의 프로버넌스 데이터를 담을 수 없다고 명세가 못 박고 있어, BMP 내보내기를 허용하면 파일 층 매니페스트가 사라지기 때문이다. 한편 클라우드 경로에서 원격 엔드포인트가 워터마킹·프로버넌스 단계 이전의 원본 이미지를 반환하도록 유도할 수 있다면 두 신호 모두 없는 이미지를 얻을 여지가 있다는 지적도 나온다. 다만 이것이 의도된 동작인지 제품 버그인지 보안 취약점인지는 마이크로소프트가 설정한 신뢰 경계를 알아야 판단할 수 있어, 현재로선 세 가능성이 모두 열려 있다.

마이크로소프트는 Image Creator 지원 페이지에서 원격 콘텐츠 필터링과 C2PA 매니페스트 부착, 그리고 남용 방지를 위해 프롬프트와 함께 사용자·기기 식별자를 수집한다는 사실을 이미 공개하고 있다. 그러나 그 C2PA 매니페스트가 눈에 보이지 않는 픽셀 워터마크의 GUID를 담고 있다는 점, 로컬 생성 경로조차 그 GUID를 원격 프롬프트 조정에서 받아온다는 점은 설명하지 않는다. '콘텐츠 자격증명'이라는 명칭 자체는 정확하지만, 그것이 프롬프트와 연결된 생성별 고유 식별자를 품고 있다는 사실을 일반 사용자가 알아차리긴 어렵다. 결국 파일 층 매니페스트와 픽셀 층 워터마크는 별개의 AI 표식이 아니라 하나의 프로버넌스 시스템을 이루는 두 층이며, 로컬 생성물에도 서버 발급 식별자가 따라붙는다는 점을 실무자는 전제로 삼아야 한다. 이 분석은 자체 검증된 리버스 엔지니어링 결과로, 향후 마이크로소프트의 공식 설명이나 사양 변경이 있을 경우 세부는 달라질 수 있다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://xusheng.dev/posts/reversing/mspaint_invisible_waterm...
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기
처리 중...