AntiAccessChk更新 v1.11

NTカーネルが実装するアクセスチェックを無効化します。基本的にはカーネル関数インラインフックのサンプルとしての位置づけです(AntiAccessChk.cab - Readme

更新内容

  1.10→1.11
    [sys]
    ・3GBブートオプション指定時に即死していた問題を修正(thank's 名無し)

カーネルの書き込み違反の回避

AntiAccessChk v1.10 について3GBオブション指定時に即死するという指摘を受けたので、対応した際の覚書。まずは v1.10時点のメモリパッチの実装部分。

// フック解除
bool UnHook() const
{
  if (this->IsValid() == false || this->IsHooked() == false) return false;
  SERIALIZE_CODE(false);

  // フック解除
  __asm CLI
  RtlCopyMemory(this->oldRoutineAddr, this->trampolineAddr, this->originalCodeSize);
  __asm STI
  __asm WBINVD
  return true;
}

要するにプロセッサの割り込みを禁止して書き込みしているだけ(余談だけど、この割り込み禁止は別CPUには反映されないため、必ず他CPUとの競合を避ける必要がある)。ゆえに対象アドレスが書込み禁止属性になっていたりすると青画面Bug Check 0xBE: ATTEMPTED_WRITE_TO_READONLY_MEMORY)が発生する。

詳しい理屈は知らないが、3GBオプション時は同じシンボルでも属性が変化するらしく、3GBのときだけ青画面になっていた、というわけ。そこでMDLを変更することでこの問題を解決できる。

//...
  // MDLの情報を更新
  MDL* mdl = MmCreateMdl(NULL, this->oldRoutineAddr, this->originalCodeSize);
  if (!mdl) return false;
  MmBuildMdlForNonPagedPool(mdl);
  mdl->MdlFlags = mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
  void* address = MmMapLockedPages(mdl, KernelMode);

  // フック解除
  __asm CLI
  RtlCopyMemory(address, this->trampolineAddr, this->originalCodeSize);
  __asm STI
  __asm WBINVD

  MmUnmapLockedPages(address, mdl);
  IoFreeMdl(mdl);
  return true;
}


できると思ったんだけど、なぜか2000では同じように青画面に行ってしまう。なぜだ。しょうがないので、さらにdirtyな方法を使ってみる。

// リアルモード(保護なし)への移行
inline void enter_real_mode()
{
  _asm
  {
    CLI
    MOV EAX,  CR0
    AND EAX,  NOT 10000H
    MOV CR0,  EAX
  }
}


// プロテクトモード(通常)への移行
inline void enter_protect_mode()
{
  _asm
  {
    MOV EAX,  CR0
    OR  EAX,  10000H
    MOV CR0,  EAX
    STI
  }
}
//...
  // フック解除
  enter_real_mode();
  RtlCopyMemory(this->oldRoutineAddr, this->trampolineAddr, this->originalCodeSize);
  enter_protect_mode();

  return true;
}

これは CR0 Trick と呼ばれるもので、一時的にCPUの書き込み保護機能を無効にする働きがある。とりあえずはこれで解決したように思われる。勉強になりました。