114114#include " tlsmon.h"
115115
116116
117- struct ssl_generate_master_key_result_t : public call_result_t
117+ static std::optional<std::string> ssl_get_master_key (
118+ drakvuf_t drakvuf, drakvuf_trap_info* info, vmi_instance_t vmi, access_context_t ctx
119+ )
118120{
119- addr_t master_key_handle_addr;
120- addr_t parameter_list_addr;
121- ssl_generate_master_key_result_t (): call_result_t (), master_key_handle_addr(), parameter_list_addr() {}
122- };
121+ tlsmon_priv::ssl_master_secret_t master_secret;
122+
123+ // We first extract master key by tracing down relevant structures starting with master_key_handle.
124+ addr_t ncrypt_ssl_key_addr = drakvuf_get_function_argument (drakvuf, info, 2 );
125+
126+ // master_key_handle points to NCryptSslKey structure.
127+ tlsmon_priv::ncrypt_ssl_key_t ncrypt_ssl_key;
128+ ctx.addr = ncrypt_ssl_key_addr;
129+ if (VMI_SUCCESS != vmi_read (vmi, &ctx, sizeof (ncrypt_ssl_key), &ncrypt_ssl_key, nullptr ))
130+ {
131+ PRINT_DEBUG (" [TLSMON] Can't read NCryptSslKey structure\n " );
132+ return {};
133+ }
134+
135+ // We can validate that we indeed found NCryptSslKey by checking magic bytes value.
136+ if (ncrypt_ssl_key.magic != tlsmon_priv::NCRYPT_SSL_KEY_MAGIC_BYTES)
137+ {
138+ PRINT_DEBUG (" [TLSMON] Wrong NCryptSslKey magic\n " );
139+ return {};
140+ }
141+
142+ // NCryptSslKey contains a pointer to SslMasterSecret structure.
143+ ctx.addr = (addr_t ) ncrypt_ssl_key.master_secret ;
144+ if (VMI_SUCCESS != vmi_read (vmi, &ctx, sizeof (master_secret), &master_secret, nullptr ))
145+ {
146+ PRINT_DEBUG (" [TLSMON] Can't read SslMasterSecret structure\n " );
147+ return {};
148+ }
149+
150+ // Again we can validate that we found SslMasterSecret structure bychecking magic bytes.
151+ if (master_secret.magic != tlsmon_priv::MASTER_SECRET_MAGIC_BYTES)
152+ {
153+ PRINT_DEBUG (" [TLSMON] Wrong SslMasterSecret magic\n " );
154+ return {};
155+ }
156+
157+ // Output retrieved master secret in hex format.
158+ std::string master_key_str = tlsmon_priv::byte2str (master_secret.master_key , tlsmon_priv::MASTER_KEY_SZ);
159+ return master_key_str;
160+ }
161+
162+ static
163+ std::optional< std::vector<tlsmon_priv::ncrypt_buffer_t > > ssl_get_ncrypt_buffers (
164+ drakvuf_t drakvuf, drakvuf_trap_info* info, vmi_instance_t vmi, access_context_t ctx
165+ )
166+ {
167+ // Now retrieve client random and server random values. pParameterList points to an array of
168+ // NCryptBuffer buffers which contains at least client and server random
169+ // values.
170+ ctx.addr = drakvuf_get_function_argument (drakvuf, info, 5 );
171+ tlsmon_priv::ncrypt_buffer_desc_t ncrypt_buffer_desc;
172+ if (VMI_SUCCESS != vmi_read (vmi, &ctx, sizeof (ncrypt_buffer_desc), &ncrypt_buffer_desc, nullptr ))
173+ {
174+ PRINT_DEBUG (" [TLSMON] Failed to read ncrypt parameter list\n " );
175+ return {};
176+ }
177+
178+ size_t ncrypt_buffers_size = ncrypt_buffer_desc.cbuffers ;
179+ if ( ncrypt_buffers_size != 2 )
180+ {
181+ PRINT_DEBUG (" [TLSMON] Ncrypt parameter list has different size than 2\n " );
182+ return {};
183+ }
184+
185+ std::vector<tlsmon_priv::ncrypt_buffer_t > ncrypt_buffers = std::vector<tlsmon_priv::ncrypt_buffer_t >(ncrypt_buffers_size);
186+ ctx.addr = (addr_t ) ncrypt_buffer_desc.buffers ;
187+ if (VMI_SUCCESS != vmi_read (vmi, &ctx, (ncrypt_buffers_size * sizeof (tlsmon_priv::ncrypt_buffer_t )), ncrypt_buffers.data (), nullptr ))
188+ {
189+ PRINT_DEBUG (" [TLSMON] Failed to read ncrypt parameter list buffers\n " );
190+ return {};
191+ }
192+ return ncrypt_buffers;
193+ }
123194
124195
125196/* *
126- * Extracts and logs 48-bytes-long master key along with client random which
127- * can be then loaded to wireshark to automatically decrypt the TLS traffic .
197+ * Sets a trap on return from SslGenerateSessionKeys function to obtain the
198+ * calculated master key .
128199 */
129200static
130- event_response_t ssl_generate_master_key_ret_cb (drakvuf_t drakvuf, drakvuf_trap_info* info)
201+ event_response_t ssl_generate_session_keys_cb (drakvuf_t drakvuf, drakvuf_trap_info* info)
131202{
132- auto plugin = get_trap_plugin<tlsmon>(info);
133- auto params = get_trap_params<ssl_generate_master_key_result_t >(info);
134- if (!params->verify_result_call_params (drakvuf, info))
135- return VMI_EVENT_RESPONSE_NONE;
136-
203+ auto plugin = static_cast <tlsmon*>(drakvuf_get_extra_from_running_trap (info->trap ));
137204 ACCESS_CONTEXT (ctx,
138205 .translate_mechanism = VMI_TM_PROCESS_DTB,
139206 .dtb = info->regs ->cr3
140207 );
141208
142- tlsmon_priv::ssl_master_secret_t master_secret;
143- std::array<char , tlsmon_priv::CLIENT_RANDOM_SZ> client_random = std::array<char , tlsmon_priv::CLIENT_RANDOM_SZ>();
144- {
145- auto vmi = vmi_lock_guard (drakvuf);
146- // We first extract master key by tracing down relevant structures starting
147- // with master_key_handle.
148- addr_t ncrypt_sll_key_addr = 0 ;
149- ctx.addr = params->master_key_handle_addr ;
150- if (VMI_SUCCESS != vmi_read_addr (vmi, &ctx, &ncrypt_sll_key_addr))
151- {
152- plugin->destroy_trap (info->trap );
153- return VMI_EVENT_RESPONSE_NONE;
154- }
209+ auto vmi = vmi_lock_guard (drakvuf);
155210
156- // master_key_handle points to NCryptSslKey structure.
157- tlsmon_priv::ncrypt_ssl_key_t ncrypt_ssl_key;
158- ctx.addr = ncrypt_sll_key_addr;
159- if (VMI_SUCCESS != vmi_read (vmi, &ctx, sizeof (ncrypt_ssl_key), &ncrypt_ssl_key, nullptr ))
160- {
161- plugin->destroy_trap (info->trap );
162- return VMI_EVENT_RESPONSE_NONE;
163- }
164- // We can validate that we indeed found NCryptSslKey by checking magic
165- // bytes value.
166- if (ncrypt_ssl_key.magic != tlsmon_priv::NCRYPT_SSL_KEY_MAGIC_BYTES)
167- {
168- plugin->destroy_trap (info->trap );
169- return VMI_EVENT_RESPONSE_NONE;
170- }
211+ auto master_key = ssl_get_master_key (drakvuf, info, vmi, ctx);
212+ if (!master_key)
213+ {
214+ return VMI_EVENT_RESPONSE_NONE;
215+ }
171216
172- // NCryptSslKey contains a pointer to SslMasterSecret structure.
173- ctx.addr = (addr_t ) ncrypt_ssl_key.master_secret ;
174- if (VMI_SUCCESS != vmi_read (vmi, &ctx, sizeof (master_secret), &master_secret, nullptr ))
175- {
176- plugin->destroy_trap (info->trap );
177- return VMI_EVENT_RESPONSE_NONE;
178- }
179- // Again we can validate that we found SslMasterSecret structure by
180- // checking magic bytes.
181- if (master_secret.magic != tlsmon_priv::MASTER_SECRET_MAGIC_BYTES)
182- {
183- plugin->destroy_trap (info->trap );
184- return VMI_EVENT_RESPONSE_NONE;
185- }
217+ auto ncrypt_buffers = ssl_get_ncrypt_buffers (drakvuf, info, vmi, ctx);
218+ if (!ncrypt_buffers)
219+ {
220+ return VMI_EVENT_RESPONSE_NONE;
221+ }
186222
223+ // buffer for both ClientRandom and ServerRandom
224+ std::array<char , tlsmon_priv::CLIENT_RANDOM_SZ> randoms_buffer = std::array<char , tlsmon_priv::CLIENT_RANDOM_SZ>();
187225
188- // Now retrieve client random value. pParameterList points to an array of
189- // NCryptBuffer buffers which contains at least client and server random
190- // values.
191- ctx.addr = params->parameter_list_addr ;
192- tlsmon_priv::ncrypt_buffer_desc_t ncrypt_buffer_desc;
193- if (VMI_SUCCESS != vmi_read (vmi, &ctx, sizeof (ncrypt_buffer_desc), &ncrypt_buffer_desc, nullptr ))
226+ for (tlsmon_priv::ncrypt_buffer_t ncrypt_buffer_iter: *ncrypt_buffers)
227+ {
228+ uint32_t buffer_type = ncrypt_buffer_iter.buffer_type ;
229+ uint32_t size = ncrypt_buffer_iter.cbbuffer ;;
230+ if ( size != tlsmon_priv::CLIENT_RANDOM_SZ )
194231 {
195- plugin-> destroy_trap (info-> trap );
196- return VMI_EVENT_RESPONSE_NONE ;
232+ PRINT_DEBUG ( " [TLSMON] Wrong ncrypt buffer size \n " );
233+ continue ;
197234 }
198235
199- std::vector<tlsmon_priv:: ncrypt_buffer_t > ncrypt_buffers = std::vector<tlsmon_priv:: ncrypt_buffer_t >(ncrypt_buffer_desc. cbuffers );
200- ctx.addr = (addr_t ) ncrypt_buffer_desc. buffers ;
201- if (VMI_SUCCESS != vmi_read (vmi, &ctx, ncrypt_buffer_desc. cbuffers * sizeof (tlsmon_priv:: ncrypt_buffer_t ), ncrypt_buffers .data (), nullptr ))
236+ // read the buffer
237+ ctx.addr = (addr_t ) ncrypt_buffer_iter. buffer ;
238+ if (VMI_SUCCESS != vmi_read (vmi, &ctx, randoms_buffer. size ( ), randoms_buffer .data (), nullptr ))
202239 {
203- plugin-> destroy_trap (info-> trap );
204- return VMI_EVENT_RESPONSE_NONE ;
240+ PRINT_DEBUG ( " [TLSMON] Failed to read ncrypt buffer \n " );
241+ continue ;
205242 }
243+ // convert bytes to string
244+ std::string client_random_str = tlsmon_priv::byte2str ((unsigned char *)randoms_buffer.data (), 32 );
206245
207- // Find the buffer containing client random.
208- auto it = std::find_if (ncrypt_buffers.begin (), ncrypt_buffers.end (), [&](const auto & e)
246+ if (buffer_type == tlsmon_priv::NCRYPTBUFFER_SSL_CLIENT_RANDOM)
209247 {
210- return e.buffer_type == tlsmon_priv::NCRYPTBUFFER_SSL_CLIENT_RANDOM;
211- });
212- if (it == ncrypt_buffers.end ())
213- {
214- plugin->destroy_trap (info->trap );
215- return VMI_EVENT_RESPONSE_NONE;
248+ fmt::print (plugin->m_output_format , " tlsmon" , drakvuf, info,
249+ keyval (" client_random" , fmt::Qstr (client_random_str)),
250+ keyval (" master_key" , fmt::Qstr (*master_key))
251+ );
216252 }
217-
218- // And finally read it.
219- ctx.addr = (addr_t ) it->buffer ;
220- if (VMI_SUCCESS != vmi_read (vmi, &ctx, client_random.size (), client_random.data (), nullptr ))
253+ else if (buffer_type != tlsmon_priv::NCRYPTBUFFER_SSL_SERVER_RANDOM)
221254 {
222- plugin-> destroy_trap (info-> trap );
223- return VMI_EVENT_RESPONSE_NONE ;
255+ PRINT_DEBUG ( " [TLSMON] Unknown ncrypt buffer type. \n " );
256+ continue ;
224257 }
225- } // Unlock vmi.
226-
227- // Output retrieved data in hex format.
228- std::string master_key_str = tlsmon_priv::byte2str (master_secret.master_key , tlsmon_priv::MASTER_KEY_SZ);
229- std::string client_random_str = tlsmon_priv::byte2str ((unsigned char *)client_random.data (), tlsmon_priv::CLIENT_RANDOM_SZ);
230- fmt::print (plugin->m_output_format , " tlsmon" , drakvuf, info,
231- keyval (" client_random" , fmt::Qstr (client_random_str)),
232- keyval (" master_key" , fmt::Qstr (master_key_str))
233- );
234-
235- plugin->destroy_trap (info->trap );
236- return VMI_EVENT_RESPONSE_NONE;
237- }
238-
239-
240- /* *
241- * Sets a trap on return from SslGenerateMasterKey function to obtain the
242- * calculated master key.
243- */
244- static
245- event_response_t ssl_generate_master_key_cb (drakvuf_t drakvuf, drakvuf_trap_info* info)
246- {
247- auto plugin = static_cast <tlsmon*>(drakvuf_get_extra_from_running_trap (info->trap ));
248- auto trap = plugin->register_trap <ssl_generate_master_key_result_t >(
249- info,
250- ssl_generate_master_key_ret_cb,
251- breakpoint_by_dtb_searcher (),
252- " SslGenerateMasterKey"
253- );
254- if (!trap)
255- return VMI_EVENT_RESPONSE_NONE;
256-
257- auto params = get_trap_params<ssl_generate_master_key_result_t >(trap);
258- params->set_result_call_params (info);
259- params->master_key_handle_addr = drakvuf_get_function_argument (drakvuf, info, 4 );
260- params->parameter_list_addr = drakvuf_get_function_argument (drakvuf, info, 7 );
261-
258+ }
262259 return VMI_EVENT_RESPONSE_NONE;
263260}
264261
@@ -274,7 +271,7 @@ void tlsmon::hook_lsass(drakvuf_t drakvuf)
274271 addr_t lsass_base = 0 ;
275272 if (!drakvuf_find_process (drakvuf, ~0 , " lsass.exe" , &lsass_base))
276273 return ;
277- drakvuf_request_userhook_on_running_process (drakvuf, lsass_base, " ncrypt.dll" , " SslGenerateMasterKey " , ssl_generate_master_key_cb , this );
274+ drakvuf_request_userhook_on_running_process (drakvuf, lsass_base, " ncrypt.dll" , " SslGenerateSessionKeys " , ssl_generate_session_keys_cb , this );
278275}
279276
280277
0 commit comments