Skip to main content

windows_reactor/
ncrypt.rs

1use vmi::{
2    Va, VmiContext, VmiError, VmiOs,
3    driver::VmiRead,
4    os::windows::{ArchAdapter, WindowsOs},
5    utils::reactor::Action,
6};
7use zerocopy::{FromBytes, IntoBytes};
8
9const NCRYPTBUFFER_SSL_CLIENT_RANDOM: u32 = 20;
10//const NCRYPTBUFFER_SSL_SERVER_RANDOM: u32 = 21;
11
12#[repr(C)]
13#[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
14struct NCryptBuffer {
15    cbBuffer: u32,   // ULONG
16    BufferType: u32, // ULONG
17    pvBuffer: u64,   // PVOID (pointer to the buffer)
18}
19
20#[repr(C)]
21#[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
22struct NCryptBufferDesc {
23    ulVersion: u32, // ULONG
24    cBuffers: u32,  // ULONG
25    pBuffers: u64,  // NCryptBuffer*
26}
27
28#[repr(C)]
29#[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
30struct SSL_MASTER_KEY {
31    cbLength: u32,          // ULONG
32    dwMagic: u32,           // ULONG
33    dwProtocol: u32,        // ULONG
34    _pad: u32,              // Padding to align the next field to 8 bytes.
35    pCipherSuite: u64,      // const SSL_CIPHER_SUITE*
36    fClient: i32,           // BOOL
37    rgbMasterKey: [u8; 48], // UCHAR[48]
38    cbMasterKey: u32,       // ULONG
39}
40
41#[repr(C)]
42#[derive(Debug, Copy, Clone, FromBytes, IntoBytes)]
43struct NCRYPT_SSL_KEY {
44    cbLength: u32,  // ULONG
45    dwMagic: u32,   // ULONG
46    dwFlags: u32,   // ULONG
47    RefCount: i32,  // LONG
48    hSubKey: u64,   // NCRYPT_KEY_HANDLE (eg. SSL_MASTER_KEY*)
49    pProvider: u64, // NCRYPT_SSL_PROVIDER*
50}
51
52/// Demonstrates how to monitor `SslGenerateSessionKeys` calls in `ncrypt.dll`
53/// and log the master key and client random used in the SSL/TLS session key
54/// generation.
55///
56/// This can be used to decrypt the SSL/TLS traffic managed by [Schannel].
57///
58/// More specifically, if the entries would be saved into a `SSLKEYLOGFILE` as
59/// `CLIENT_RANDOM <client_random> <secret>`, then Wireshark can use them to
60/// decrypt the SSL/TLS traffic captured in a pcap file.
61///
62/// [Schannel]: https://learn.microsoft.com/en-us/windows/win32/com/schannel
63pub fn SslGenerateSessionKeys<Driver>(
64    vmi: &VmiContext<WindowsOs<Driver>>,
65) -> Result<Action<<WindowsOs<Driver> as VmiOs>::Architecture>, VmiError>
66where
67    Driver: VmiRead,
68    Driver::Architecture: ArchAdapter<Driver>,
69{
70    //
71    // SECURITY_STATUS
72    // WINAPI
73    // SslGenerateSessionKeys(
74    //     _In_ NCRYPT_PROV_HANDLE hSslProvider,
75    //     _In_ NCRYPT_KEY_HANDLE hMasterKey,
76    //     _Out_ NCRYPT_KEY_HANDLE *phReadKey,
77    //     _Out_ NCRYPT_KEY_HANDLE *phWriteKey,
78    //     _In_ PNCryptBufferDesc pParameterList,
79    //     _In_ DWORD dwFlags
80    //     );
81    //
82
83    let hMasterKey = vmi.os().function_argument(1)?;
84    let pParameterList = vmi.os().function_argument(4)?;
85
86    let mut client_random = vec![0u8; 32];
87
88    let parameter_list = vmi.read_struct::<NCryptBufferDesc>(Va(pParameterList))?;
89    for i in 0..parameter_list.cBuffers {
90        let offset = (i as u64) * size_of::<NCryptBuffer>() as u64;
91        let buffer = vmi.read_struct::<NCryptBuffer>(Va(parameter_list.pBuffers + offset))?;
92
93        if buffer.BufferType == NCRYPTBUFFER_SSL_CLIENT_RANDOM {
94            vmi.read(Va(buffer.pvBuffer), &mut client_random)?;
95            break;
96        }
97    }
98
99    let master_key = vmi.read_struct::<NCRYPT_SSL_KEY>(Va(hMasterKey))?;
100    let subkey = vmi.read_struct::<SSL_MASTER_KEY>(Va(master_key.hSubKey))?;
101
102    tracing::info!(
103        client_random = hex::encode(client_random),
104        secret = hex::encode(subkey.rgbMasterKey),
105    );
106
107    Ok(Action::default())
108}