
すべてのActive Directoryデータは、データベースのntds.ditファイルに保存されます。 大部分のアプリケーションは、ntdsa.dllに実装されているDSAレイヤーを介してディレクトリと対話します。 同様に、ntdsa.dllの関数はntds.ditで直接動作せず、その機能はディレクトリサービスのニーズによって制限され、Active Directoryデータベースの内部構造を把握することはできません。 ただし、ntds.ditはJET Blueデータベースにすぎません。 Windowsの各バージョン(Windows 2000以降)には、このデータベースを操作するために必要なものがすべて揃っています。
以下の記事では、次の問題を強調します。
- データベースの構造は何ですか?
- ntds.ditのデータはどのように「ツリー」を生成しますか?
- グループメンバーシップはどのように実装されますか?
- replPropertyMetaData属性の形式は何ですか?また、タイムスタンプはレプリケーションメタデータにどの程度正確に保存されますか?
ntds.ditを見るには何が必要ですか?
少なくとも: esent.dll
ESENT APIを介してさまざまなプログラミング言語を「快適に」使用するために、さまざまな「ラッパー」があります。 Meneged EsentをC#とともに使用しました 。 プロジェクトのサイトには多くの例がありますので、後でntds.ditのコンテンツに焦点を当てようとします。
また、JET BlueデータベースにはPageSizeなどのパラメーターがあることに注意してください。 デフォルトでは、4096です(私が遭遇したesent.dllのバージョンの場合)。 したがって、ntds.ditでは、ページサイズは8192であり、このパラメーターはデータベースを開く前に正しく設定する必要があります。
ESENT APIにはいくつかのバージョンがあります。 これらのバージョンには互換性がありません! そのため、Windows Server 2008 R2のntds.ditはWindows XPでは開かず、Windoes 7でのみ開きます(後方互換性はチェックしませんでした)。
質問1:データベースの構造は何ですか?
GetTableNames関数は、データベース内のテーブルのリストを返します。
datatable-すべてのカタログデータを含むメインテーブル
隠れた
link_table - technetの記事によると、関連する属性(MemberOfなど)に関する情報を含むテーブル
quota_rebuild_progress_table
quota_table
sdpropcounttable
sd_table - technetの記事によると、テーブルには各ディレクトリオブジェクトの継承されたアクセスルールに関する情報が含まれています。
データテーブルの表を見てみましょう。 列のリストは次のようになります(スクリーンショットの最初の数行)。

行き止まり? いや!
ほとんどの列名は、ATT形式<1文字のラテン文字> <数値コード>です。 したがって、このデジタルコードは、Active Directory属性の一意の識別子です。 テーブルには、列のデジタルコードの値がその値と一致する行が1つあります。 この行からテキストタイプのすべての値を推測すると、これが属性「attributeID」の定義であることがわかります。
現在、テーブルのすべての列をActive Directoryの属性と一致させることを妨げるものはありません(テーブルは例です-短縮されています。そうでない場合、投稿に収まりませんでした)。
JET_COLUMNID | 列名 | ジェットコラムタイプ | AD属性名 | |
---|---|---|---|---|
JET_COLUMNID(0x6) | ab_cnt_col | 長い | 単一値 | |
JET_COLUMNID(0x100) | 祖先_col | ロングバイナリ | 単一値 | |
JET_COLUMNID(0x536) | ATTb131079 | 長い | subRefs | 多値 |
JET_COLUMNID(0x121) | ATTb131088 | 長い | nCName | 多値 |
JET_COLUMNID(0x2dd) | ATTb131108 | 長い | dMDLocation | 多値 |
JET_COLUMNID(0x42c) | ATTb1376270 | 長い | documentAuthor | 多値 |
JET_COLUMNID(0x169) | ATTb1376277 | 長い | 秘書 | 多値 |
JET_COLUMNID(0x2b8) | ATTb1376294 | 長い | relatedName | 多値 |
JET_COLUMNID(0x470) | ATTb33 | 長い | roleOccupant | 多値 |
JET_COLUMNID(0x203) | ATTb34 | 長い | また見よ | 多値 |
JET_COLUMNID(0x2d2) | ATTb49 | 長い | 識別名 | 多値 |
JET_COLUMNID(0x4cc) | ATTb50 | 長い | uniqueMember | 多値 |
JET_COLUMNID(0x206) | ATTb589856 | 長い | domainPolicyObject | 多値 |
JET_COLUMNID(0x250) | ATTb589864 | 長い | fromServer | 多値 |
JET_COLUMNID(0x205) | ATTb589881 | 長い | defaultLocalPolicyObject | 多値 |
JET_COLUMNID(0x1cc) | ATTb589921 | 長い | preferredOU | 多値 |
JET_COLUMNID(0x5a6) | ATTb590037 | 長い | defaultClassStore | 多値 |
JET_COLUMNID(0x270) | ATTb590038 | 長い | nextLevelStore | 多値 |
JET_COLUMNID(0x183) | ATTb590127 | 長い | notificationList | 多値 |
JET_COLUMNID(0x238) | ATTb590192 | 長い | rIDManagerReference | 多値 |
JET_COLUMNID(0x57c) | ATTb590193 | 長い | fSMORoleOwner | 多値 |
JET_COLUMNID(0x3c8) | ATTb590246 | 長い | domainPolicyReference | 多値 |
JET_COLUMNID(0x566) | ATTb590281 | 長い | localPolicyReference | 多値 |
JET_COLUMNID(0x3c1) | ATTb590295 | 長い | trustParent | 多値 |
JET_COLUMNID(0x4c1) | ATTb590296 | 長い | domainCrossRef | 多値 |
JET_COLUMNID(0x5bc) | ATTb590304 | 長い | defaultGroup | 多値 |
JET_COLUMNID(0x57f) | ATTb590318 | 長い | siteServer | 多値 |
JET_COLUMNID(0x532) | ATTb590338 | 長い | physicalLocationObject | 多値 |
JET_COLUMNID(0x563) | ATTb590341 | 長い | ipsecPolicyReference | 多値 |
JET_COLUMNID(0x24f) | ATTb590361 | 長い | dynamicLDAPServer | 多値 |
JET_COLUMNID(0x1a4) | ATTb590381 | 長い | parentCA | 多値 |
JET_COLUMNID(0x233) | ATTb590448 | 長い | ipsecOwnersReference | 多値 |
JET_COLUMNID(0x345) | ATTq590722 | 通貨 | aCSNonReservedTxSize | 多値 |
JET_COLUMNID(0x398) | ATTq591137 | 通貨 | aCSMaxTokenBucketPerFlow | 多値 |
JET_COLUMNID(0x19b) | ATTq591138 | 通貨 | aCSMaximumSDUSize | 多値 |
JET_COLUMNID(0x4d3) | ATTq591139 | 通貨 | aCSMinimumPolicedSize | 多値 |
JET_COLUMNID(0x244) | ATTq591140 | 通貨 | aCSMinimumLatency | 多値 |
JET_COLUMNID(0x12f) | ATTq591141 | 通貨 | aCSMinimumDelayVariation | 多値 |
JET_COLUMNID(0x16e) | ATTq591142 | 通貨 | aCSNonReservedPeakRate | 多値 |
JET_COLUMNID(0x344) | ATTq591143 | 通貨 | aCSNonReservedTokenSize | 多値 |
JET_COLUMNID(0x4d4) | ATTq591144 | 通貨 | aCSNonReservedMaxSDUSize | 多値 |
JET_COLUMNID(0x343) | ATTq591145 | 通貨 | aCSNonReservedMinPolicedSize | 多値 |
JET_COLUMNID(0x5ac) | ATTq591191 | 通貨 | mS-SQL-Memory | 多値 |
JET_COLUMNID(0x213) | ATTq591204 | 通貨 | mS-SQL-Status | 多値 |
JET_COLUMNID(0x4d5) | ATTq591220 | 通貨 | mS-SQL-サイズ | 多値 |
JET_COLUMNID(0x2c5) | ATTq591266 | 通貨 | msDS-Cached-Membership-Time-Stamp | 多値 |
JET_COLUMNID(0x548) | ATTq591456 | 通貨 | msWMI-Int8Default | 多値 |
JET_COLUMNID(0x52a) | ATTq591457 | 通貨 | msWMI-Int8Max | 多値 |
JET_COLUMNID(0x53f) | ATTq591458 | 通貨 | msWMI-Int8Min | 多値 |
JET_COLUMNID(0x214) | ATTq591459 | 通貨 | msWMI-Int8ValidValues | 多値 |
JET_COLUMNID(0x2c1) | ATTq591520 | 通貨 | lastLogonTimestamp | 多値 |
JET_COLUMNID(0x2cc) | ATTq591794 | 通貨 | msDS-LastSuccessfulInteractiveLogonTime | 多値 |
JET_COLUMNID(0x462) | ATTq591795 | 通貨 | msDS-LastFailedInteractiveLogonTime | 多値 |
JET_COLUMNID(0x440) | ATTq591835 | 通貨 | msDS-MaximumPasswordAge | 多値 |
JET_COLUMNID(0x2a5) | ATTq591836 | 通貨 | msDS-MinimumPasswordAge | 多値 |
JET_COLUMNID(0x200) | ATTq591841 | 通貨 | msDS-LockoutObservationWindow | 多値 |
JET_COLUMNID(0x2e7) | ATTq591842 | 通貨 | msDS-LockoutDuration | 多値 |
JET_COLUMNID(0x3d0) | ATTq591879 | 通貨 | msDS-USNLastSyncSuccess | 多値 |
JET_COLUMNID(0x49a) | ATTq591922 | 通貨 | msDS-ClaimValueType | 多値 |
JET_COLUMNID(0x476) | ATTq592002 | 通貨 | msKds-UseStartTime | 多値 |
JET_COLUMNID(0x477) | ATTq592003 | 通貨 | msKds-CreateTime | 多値 |
JET_COLUMNID(0x3a0) | ATTq592007 | 通貨 | msDS-GeoCoordinatesAltitude | 多値 |
JET_COLUMNID(0x3a1) | ATTq592008 | 通貨 | msDS-GeoCoordinatesLatitude | 多値 |
JET_COLUMNID(0x3a2) | ATTq592009 | 通貨 | msDS-GeoCoordinatesLongitude | 多値 |
JET_COLUMNID(0x43b) | ATTr589945 | ロングバイナリ | securityIdentifier | 多値 |
JET_COLUMNID(0x1c9) | ATTr589970 | ロングバイナリ | objectSid | 多値 |
JET_COLUMNID(0x276) | ATTr590433 | ロングバイナリ | sIDHistory | 多値 |
JET_COLUMNID(0x443) | ATTr590491 | ロングバイナリ | syncWithSID | 多値 |
JET_COLUMNID(0x5e4) | ATTr591234 | ロングバイナリ | mS-DS-CreatorSID | 多値 |
JET_COLUMNID(0x50a) | ATTr591668 | ロングバイナリ | msDS-QuotaTrustee | 多値 |
JET_COLUMNID(0x1c2) | ATTr591978 | ロングバイナリ | msAuthz-CentralAccessPolicyID | 多値 |
JET_COLUMNID(0x5) | cnt_col | 長い | 単一値 | |
JET_COLUMNID(0x1) | DNT_col | 長い | 単一値 | |
JET_COLUMNID(0x5f1) | extendedprocesslinks_col | ロングバイナリ | 単一値 | |
JET_COLUMNID(0x9) | IsVisibleInAB | UnsignedByte | 単一値 | |
JET_COLUMNID(0x8) | NCDNT_col | 長い | 単一値 | |
JET_COLUMNID(0x3) | Obj_col | UnsignedByte | 単一値 | |
JET_COLUMNID(0x2) | PDNT_col | 長い | 単一値 | |
JET_COLUMNID(0x4) | RDNtyp_col | 長い | 単一値 | |
JET_COLUMNID(0xa) | recycle_time_col | 通貨 | 単一値 | |
JET_COLUMNID(0x7) | time_col | 通貨 | 単一値 |
「暗号化されていない」ATTc0属性が1つ残っています。これは「objectClass」への参照です。
Active Directoryの属性を格納するすべての列は、スキームに関係なく複数値として設定されることに注意してください。
質問2:ntds.ditのデータはどのように「ツリー」ですか?
列名「DNT_col」は、それが何らかの形でオブジェクトのdistinguishedNameに関連していることを示唆するように誘発します(後で判明したように、それらは等しい)
DNT_col列の値は1で始まり、DNT_col = 1の行は、属性値name = "$ NOT_AN_OBJECT1 $"を持つ興味深いオブジェクトに対応します。
DNT_col = 2の行には、「$ ROOT_OBJECT $」という名前のオブジェクトの属性が含まれています(RootDSEと混同しないでください)
DNT_col = 6で、objectClass定義が始まります
別の行き止まり? もういや!
他の方法で行きましょう。
タイプ「Administrator」の値のATTm589825(名前)列での検索は、DNT_col = 3841およびPDNT_col = 1951のレコードを返しました。
ATTm589825(名前)列でテキスト「ユーザー」タイプの値(標準管理者アカウントが配置されているコンテナ)を検索すると、DNT_col = 1951およびPDNT_col = 1944のエントリが返されました
これが接続です! PDNT_col列には、親オブジェクトのDNT_col識別子が含まれています。
DNT_col = 1944(PDNT_col = 1943)の行-第2レベルドメインオブジェクトがありました(ntds.ditは第2レベルドメインコントローラーから取得されました)
DNT_col = 1943(PDNT_col = 2)の行-第1レベルドメインのオブジェクト。
「cn =構成のオブジェクト、dc = contoso、dc = contoso、dc = comに接続したときにdc = comが表示されないのはなぜですか?」ネーミングコンテキストオブジェクト。 (さらに、第1レベルのドメインオブジェクトには名前付けコンテキストがありません。表示されないようにすることはできますか?)。 命名コンテキスト「dc = contoso、dc = com」および「cn =構成、dc = contoso、dc = com」のオブジェクトの場合、この列の値は異なります。
これらの数値からオブジェクトの完全なdistinguishedNameがどのように取得されるかは、それほど興味深いことではありません。 オブジェクトのどの属性が相対固有名(RDN)であり、完全識別名を作成するために使用されます。
RDNtyp_col列には、RDNを含む属性識別子(attributeID)が含まれます。
CNT_col列には、現在に関連付けられているオブジェクトの数が含まれています。 この列は、 Link Cleanerによって使用されます。
OBJ_col列のビットが1に設定されている場合、この行はディレクトリオブジェクトを示します。 それ以外の場合は、ファントムオブジェクトです。
SubTree検索はどのように実装されますか?
このような構造では、OneLavelを検索するには、PDNT_colが検索ベースのDNに等しいレコードを検索するだけで十分ですが、SubTreeで検索するにはどうすればよいでしょうか? すべての支店を回る? いいえ、複雑すぎます。
Ancestors_colという名前の列の値を見てみましょう。 階層内のオブジェクトが深いほど、この列の値が長くなることは印象的です。 ネストレベルごとに、長さが4バイト追加されます。 これは、親オブジェクトの優先順位のリストに過ぎません。
さらに、リストはdn = 2で始まります。 「$ ROOT_OBJECT $」
Ancestors_colを最新の状態に保つのは誰ですか? 文書によると、オブジェクトを新しい場所に移動すると、そのPDNT_colのみが変更され、Ancestors_colの値は、オブジェクトにアクセスするための新しいルールが再カウントされると同時にSDPropメカニズムによって更新されます。
質問3:グループメンバーシップはどのように実装されますか?
2003年以降、サーバーにはグループに無制限の数のユーザーを含める機会があり、文字列または数値の複数値属性に最大1200を超える値を書き込むことができないのはなぜですか?
はい。「member」と「memberOf」はリンクとして定義されているためです。 これらの属性に一致するデータテーブルの列はありません。 これらの属性の値は、別個のlink_tableのマッピングとして実装されます。
おそらくこれが、(RecucleBinを使用せずに)グループを削除すると、そのメンバーに関する情報を失うためです- 削除されたオブジェクトをコンテナーに移動すると、リモートグループのオブジェクトはDNT_colで新しい識別子を受け取ります (グループとそのメンバーの接続はこの識別子を使用して構築されます)
link_tableの列を見てみましょう
JET_COLUMNID(0x2) | backlink_DNT | 長い | 単一値 |
JET_COLUMNID(0x3) | link_base | 長い | 単一値 |
JET_COLUMNID(0x100) | link_data | ロングバイナリ | 単一値 |
JET_COLUMNID(0x4) | link_deactivetime | 通貨 | 単一値 |
JET_COLUMNID(0x5) | link_deltime | 通貨 | 単一値 |
JET_COLUMNID(0x1) | link_DNT | 長い | 単一値 |
JET_COLUMNID(0x80) | link_metadata | バイナリ | 単一値 |
JET_COLUMNID(0x7) | link_ncdnt | 長い | 単一値 |
JET_COLUMNID(0x101) | link_ndesc | 長い | 単一値 |
JET_COLUMNID(0x6) | link_usnchanged | 通貨 | 単一値 |
列の名前とタイプがヒントになり、列に含まれるデータの分析により次のことが確認されます。
link_DNT-通信が記述されているオブジェクト(グループオブジェクトなど)の識別子dn(データテーブルのDNT_colに対応)を含む
backlink_DNT-関連するオブジェクト(ユーザーオブジェクトなど)のdn識別子が含まれます
link_ncdnt-通信参加者が存在するネーミングコンテキストのdn識別子が含まれます。
link_usnchanged-最後の最後のUSN変更が含まれています
link_data-このフィールドは、NTDS設定オブジェクトの関連付けについてのみ入力されているのを見ました。 はい! NTDS設定オブジェクトには、ディレクトリパーティションオブジェクトとのリンクがありますが、これらのリンクを通じて、さまざまなディレクトリセクションのレプリケーションパラメータが設定されているようです。
link_deltime-リンクが削除された時刻が含まれます
link_metadata-行われた変更を複製するために必要なメタデータが含まれています。 Windows 2012では、この列の入力値のみを見ました。ChristofferAnderssonは、列にDS_REPL_VALUE_META_DATA構造が含まれて いると書いていますが、ここでは強く反対します。 DS_REPL_VALUE_META_DATA構造はより高いレベルで使用されます-ntdsa.dllの呼び出しはそれを返します。 この列に含まれるデータは、DS_REPL_VALUE_META_DATA構造の下で必要なデータよりも小さくなっています。 このコラムは私には謎のままです。 原則として、リンク属性のレプリケーションメタデータは、構築されたmsDS-ReplValueMetaData属性から取得できますが、このデータを処理および保存するための内部メカニズムは明らかにされていません。
4番目の質問:replPropertyMetaData属性の形式は何ですか?また、タイムスタンプはレプリケーションメタデータにどの程度正確に保存されますか?
この属性は、バイナリ複製メタデータを保存します

この構造の最初の8バイトに何が格納されているかはまだわかりません。
値を持つ複製された属性のみがreplPropertyMetaData構造にリストされるという事実に注意する必要があります。 したがって、たとえば、replPropertyMetaDataにlogonTimestamp属性識別子は表示されません。
興味深い点があります。ActiveDirectoryセキュリティオブジェクト(ユーザー、グループ、およびコンピューター)のreplPropertyMetaData構造には、objectSid属性が存在します。
ところで、この属性の値を解読するために-このように負担をかける必要はありません-構築された属性msDS-ReplAttributeMetaDataがあります-それはreplPropertyMetaDataの解析された値以外を表しません。
Active Directoryのタイムスタンプは、1601年1月1日00:00から経過した秒数を示す64ビットの符号なし整数です。 これには興味深いニュアンスがあります。2つのドメインコントローラー上の同じオブジェクトの1つの属性を1秒間編集すると(たとえば、多数のユーザーをバッチ処理する場合)、予期しない結果が得られます。
technetの記事によると、 GUIDが低いコントローラーの属性のバージョンが優先されます。
使用される情報:
technet.microsoft.com/en-us/library/cc772829%28v=ws.10%29.aspx
blogs.chrisse.se/2012/02/11/how-the-active-directory-data-store-really-works-inside-ntds-dit-part-1
blogs.chrisse.se/2012/02/15/how-the-active-directory-data-store-really-works-inside-ntds-dit-part-2
blogs.chrisse.se/2012/02/20/how-the-active-directory-data-store-really-works-inside-ntds-dit-part-3
blogs.chrisse.se/2012/02/28/how-the-active-directory-data-store-really-works-inside-ntds-dit-part-4
gexeg.blogspot.ru/2009/12/active-directory.html
www.ntdsxtract.com
すべての実験は、Windows Server 2012 Engのntds.ditで実行されました
UPD まず、ntds.ditを学習するために作成した小さなユーティリティ (誰かに合うかもしれません)。