Retired Microsoft Blog disclaimer

This directory is a mirror of retired "Decrypt My World" MSDN blog and is provided as is. All posting authorship and copyrights belong to respective authors.

Posts on this page:

Original URL: https://blogs.msdn.microsoft.com/alejacma/2007/11/08/how-to-trace-cryptoapi-calls-2/
Post name: How to trace CryptoAPI calls (2)
Original author: Alejandro Campos Magencio
Posting date: 2007-11-08T17:46:00+00:00


Hi, welcome back,


Let's try to understand a bit better what's going on myCryptoAPI Tracer script.


Let's take a look to one of the most important breakpoints I set on a CryptoAPI function:


bm Advapi32!CryptAcquireContextW ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptAcquireContextW (%#x)\\n\", @$tid; .echo;.echo IN; .echo pszContainer; .if(poi(@esp+8)=0) {.echo NULL} .else {du poi(@esp+8)}; .echo;.echo pszProvider; .if(poi(@esp+c)=0) {.echo NULL} .else {du poi(@esp+c)}; .echo;.echo dwProvType; .if(poi(@esp+10)=1) {.echo PROV_RSA_FULL} .elsif(poi(@esp+10)=0x18) {.echo PROV_RSA_AES} .else {.printf \"%d\\n\", poi(@esp+10)}; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+14); .if((poi(@esp+14)&0x0`F0000000)=0x0`F0000000) {.echo CRYPT_VERIFYCONTEXT(0xf0000000)}; .if((poi(@esp+14)&0x0`00000008)=0x0`00000008){.echo CRYPT_NEWKEYSET(0x8)}; .if((poi(@esp+14)&0x0`00000010)=0x0`00000010) {.echo CRYPT_DELETEKEYSET(0x10)}; .if((poi(@esp+14)&0x0`00000020)=0x0`00000020) {.echo CRYPT_MACHINE_KEYSET(0x20)}; .if((poi(@esp+14)&0x0`00000040)=0x0`00000040) {.echo CRYPT_SILENT(0x40)}; bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if(poi(@esp-14)=0) {.echo phProv;.echo NULL} .else {.echo hProv; .if(poi(poi(@esp-14))=0) {.echo NULL} .else {.printf \\\"%#x\\\\n\\\", poi(poi(@esp-14))} }; .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptAcquireContextW (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptAcquireContextW (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";


It looks a bit complex, but it's not so much. Some of the basics where already explained here.


Imagine we have the following API declaration in C:


int __stdcall myFunction(int a, int b, int c);


If I set a breakpoint on myFunction, and because we use __stdcall calling convention (the same as Win32 API/CryptoAPI functions), the stack will look this way just when we reach the breakpoint, before we run any code on myFunction:

return address <-- esp
a <-- esp+4
b <-- esp+8
c <-- esp+c
xxxxxxxx
yyyyyyyy
zzzzzzzz

"esp" (stack pointer) register will be pointing to the address where we'll return after finishing executing myFunction. If we want to i.e. access the second parameter of the function, we can use the address esp+8.


When we finish executing myFunctionand we return from it, "eax" register willcontain the return value of the API and the stack will look like this:

xxxxxxxx       <-- esp
yyyyyyyy
zzzzzzzz

Now, if we want to access one of the parameters of the API we just called (i.e. because it's an out parameter), we have to remember that the information of the stack is not cleaned. So even if "esp" register points to "xxxxxxxx" now, the parameters of the API are still on the stack:

a              <-- esp-c
b <-- esp-8
c <-- esp-4
xxxxxxxx <-- esp
yyyyyyyy
zzzzzzzz

So if we want to i.e.access the first parameter of the API we can use esp-c address.



Having said this, let's write the breakpoint above in a different way:

000 bm Advapi32!CryptAcquireContextW
001 "
002 .printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptAcquireContextW (%#x)\\n\", @$tid;
003
004 .echo;
005 .echo IN;
006
007 .echo pszContainer;
008 .if(poi(@esp+8)=0)
009 {
010 .echo NULL
011 }
012 .else
013 {
014 du poi(@esp+8)
015 };
016
017 .echo;
018 .echo pszProvider;
019 .if(poi(@esp+c)=0)
020 {
021 .echo NULL
022 }
023 .else
024 {
025 du poi(@esp+c)
026 };
027
028 .echo;
029 .echo dwProvType;
030 .if(poi(@esp+10)=1)
031 {
032 .echo PROV_RSA_FULL
033 }
034 .elsif(poi(@esp+10)=0x18)
035 {
036 .echo PROV_RSA_AES
037 }
038 .else
039 {
040 .printf \"%d\\n\", poi(@esp+10)
041 };
042
043 .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+14);
044 .if((poi(@esp+14)&0x0`F0000000)=0x0`F0000000)
045 {
046 .echo CRYPT_VERIFYCONTEXT(0xf0000000)
047 };
048 .if((poi(@esp+14)&0x0`00000008)=0x0`00000008)
049 {
050 .echo CRYPT_NEWKEYSET(0x8)
051 };
052 .if((poi(@esp+14)&0x0`00000010)=0x0`00000010)
053 {
054 .echo CRYPT_DELETEKEYSET(0x10)
055 };
056 .if((poi(@esp+14)&0x0`00000020)=0x0`00000020)
057 {
058 .echo CRYPT_MACHINE_KEYSET(0x20)
059 };
060 .if((poi(@esp+14)&0x0`00000040)=0x0`00000040)
061 {
062 .echo CRYPT_SILENT(0x40)
063 };
064
065 bp /t @$thread poi(@esp)
066 \"
067 .echo;
068 .echo OUT;
069
070 .if(poi(@esp-14)=0)
071 {
072 .echo phProv;
073 .echo NULL
074 }
075 .else
076 {
077 .echo hProv;
078 .if(poi(poi(@esp-14))=0)
079 {
080 .echo NULL
081 }
082 .else
083 {
084 .printf \\\"%#x\\\\n\\\", poi(poi(@esp-14))
085 }
086 };
087
088 .echo;
089 .echo RESULT;
090
091 .if(@eax=1)
092 {
093 .printf \\\"CryptAcquireContextW (%#x) SUCCEEDED\\\\n\\\", @$tid
094 }
095 .else
096 {
097 .printf \\\"CryptAcquireContextW (%#x) FAILED\\\\n\\\", @$tid;!gle
098 };
099
100 .echo;
101 .echo <<<<<<<<<<<<<<<<<<<<<<;
102
103 G;
104 \";
105
106 G;
107 ";

000) We set a breakpoint on the UNICODE version of CryptAcquireContext API. This is the declaration of the API:


BOOL WINAPI CryptAcquireContext(__out HCRYPTPROV* phProv,__in LPCTSTR pszContainer, __in LPCTSTR pszProvider, __in DWORD dwProvType, __in DWORD dwFlags);


The following commands will be executed when the application calls this API and we reach the breakpoint:


002) We print the name of the API and the id of the thread which calls it.


005) We print the string "IN", and after that we'll print the values of the __in parameters of the API.


007-015) We print pszContainer parameter as a string of Unicode chars,after checking if it's NULL or not.


018-026) We print pszProvider parameter as a string of Unicode chars, after checking if it's NULL or not.


029-041) We print dwProvType parameter. If we know the type we print it in clear text, otherwise we just print its numeric value.


043-063) We print dwFlags parameter in Hexadecimal. If we know the values of those flags, we print them in clear text.


065) Now we want to know what happened after the API finished executing. We set a breakpoint at the return address where we will return after calling the API. If we don't want weird things to happen on multi-threaded applications, we have to specify on which thread ("$thread" pseudo-register) we are setting that breakpoint.


106) Once we've set the breakpoint at 065, we can continue the execution of the application.


Now, let see what happens when we stop on breakpoint set at 065:


068) We print the string "OUT", and after that we'll print the values of the __out parameters of the API.


070-086) We printphProv parameter. This is a pointer to hProv. If the pointer is not NULL, we print the Hexadecimal value of hProv, after checking ifthis value isNULL or not.


089) We print the string "RESULT", and after that we'll print the return value of the API, and the error if there was one.


091-098) We show if the API succeeded or not. If not, we also show the error value that the API returned.


103) Now that we know the result of calling the API, we can continue the execution of the application and trace more APIs.




I hope this helps.


Cheers,



Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2007/10/31/cryptoapi-tracer-script/
Post name: CryptoAPI Tracer script
Original author: Alejandro Campos Magencio
Posting date: 2007-10-31T17:09:00+00:00


Hi, welcome back,


As I promised in my previous post, How to trace CryptoAPI calls, I'm posting the completescript I'm developing to trace all CryptoAPI calls being made by an application. This script shows the In & Out parameters being passed to the API, the result of calling the API, and in case of error, the error number and message that the API returned.


This script is a Beta version. I'm missing many APIs, and what I call in the script "DEFAULT TRACERS" are there to catch any API starting by Crypt* and Cert* and remind me which ones I'm missing in case I need them. Currently those default tracers are disabled.Additionally,when flags are passed to an API I try to show those flags in clear text, but I'm still missing many of them. MSDN and Platform SDK will help me complete the script. I just need time. A lot of time. There are many APIs, many parameters, many flags.


But with current version of the script I've solved many, many cases related to CryptoAPI issues very, very easily. The APIs I have already included are the most commonly used by my customers, .NET and CAPICOM.



************************************************************************
* CRYPTO API TRACER by ALEJANDRO CAMPOS MAGENCIO (BETA)
************************************************************************
*
* DISCLAIMER
*
* This sample script is not supported under any Microsoft standard
* support program or service.
* The sample script is provided as it is without warranty of any kind.
* Microsoft further disclaims all implied warranties including, without
* limitation, any implied warranties of merchantability or of fitness
* for a particular purpose.
* The entire risk arising out of the use or performance of the sample
* script remains with you. In no event shall Microsoft, its authors, or
* anyone else involved in the creation, production, or delivery of the
* script be liable for any damages whatsoever (including, without
* limitation, damages for loss of business profits, business
* interruption, loss of business information, or other pecuniary loss)
* arising out of the use of or inability to use the sample script, even
* if Microsoft has been advised of the possibility of such damages.
*
* PREREQUISITES:
*
* 1) Download the latest version of "Debugging Tools for Windows"
* http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx
*
* 2) Install the tools in any machine, and copy the directory with the
* tools to the target machine (they don't need to be installed in the
* target machine). We will use "cdb.exe" to run the script.
*
* HOW TO TRACE an already running application:
*
* - Run the following command to attach the "cdb.exe" debugger to the
* application and run the script:
* "
* cdb.exe -pn application.exe -cf "PathToScript\script.txt"
* "
*
* Note: You may target the application by PID by using "-p PID"
* instead of "-pn application.exe".
* Note: All traces will be written to log.txt in the current
* directory. You may change the path to the log file at the end
* of the script.
*
* HOW TO FINISH the tracing:
*
* A) If the application has finished execution, enter the "q" command on
* "cdb.exe" to quit the debugger.
*
* B) If the application is still running, press "Ctrl+Break" to break
* into "cdb.exe" and pause the application. Enter the "qd" command to
* detach and quit the debugger (it won't kill the target app which
* will resume execution) or "q" to just quit (it will kill the target
* app).
*
************************************************************************

************************************************************************
* DEFAULT TRACERS
************************************************************************

* Remove * to enable
*bm Advapi32!Crypt* ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\n(%#x)\\n\\n\", @$tid; .echo CALL;kb 1; bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .printf \\\"%#x\\\\n\\\\n\\\", @eax; !gle; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

* Remove * to enable
*bm Crypt32!Crypt* ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\n(%#x)\\n\\n\", @$tid; .echo CALL;kb 1; bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .printf \\\"%#x\\\\n\\\\n\\\", @eax; !gle; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

* Remove * to enable
*bm Crypt32!Cert* ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\n(%#x)\\n\\n\", @$tid; .echo CALL;kb 1; bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .printf \\\"%#x\\\\n\\\\n\\\", @eax; !gle; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

************************************************************************
* ADVAPI32!CRYPT* TRACERS
************************************************************************

bm Advapi32!CryptAcquireContextW ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptAcquireContextW (%#x)\\n\", @$tid; .echo;.echo IN; .echo pszContainer; .if(poi(@esp+8)=0) {.echo NULL} .else {du poi(@esp+8)}; .echo;.echo pszProvider; .if(poi(@esp+c)=0) {.echo NULL} .else {du poi(@esp+c)}; .echo;.echo dwProvType; .if(poi(@esp+10)=1) {.echo PROV_RSA_FULL} .elsif(poi(@esp+10)=0x18) {.echo PROV_RSA_AES} .else {.printf \"%d\\n\", poi(@esp+10)}; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+14); .if((poi(@esp+14)&0x0`F0000000)=0x0`F0000000) {.echo CRYPT_VERIFYCONTEXT(0xf0000000)}; .if((poi(@esp+14)&0x0`00000008)=0x0`00000008){.echo CRYPT_NEWKEYSET(0x8)}; .if((poi(@esp+14)&0x0`00000010)=0x0`00000010) {.echo CRYPT_DELETEKEYSET(0x10)}; .if((poi(@esp+14)&0x0`00000020)=0x0`00000020) {.echo CRYPT_MACHINE_KEYSET(0x20)}; .if((poi(@esp+14)&0x0`00000040)=0x0`00000040) {.echo CRYPT_SILENT(0x40)}; bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if(poi(@esp-14)=0) {.echo phProv;.echo NULL} .else {.echo hProv; .if(poi(poi(@esp-14))=0) {.echo NULL} .else {.printf \\\"%#x\\\\n\\\", poi(poi(@esp-14))} }; .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptAcquireContextW (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptAcquireContextW (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptAcquireContextA ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptAcquireContextA (%#x)\\n\", @$tid; .echo;.echo IN; .echo pszContainer; .if(poi(@esp+8)=0) {.echo NULL} .else {da poi(@esp+8)}; .echo;.echo pszProvider; .if(poi(@esp+c)=0) {.echo NULL} .else {da poi(@esp+c)}; .echo;.echo dwProvType; .if(poi(@esp+10)=1) {.echo PROV_RSA_FULL} .elsif(poi(@esp+10)=24) {.echo PROV_RSA_AES} .else {.printf \"%d\\n\", poi(@esp+10)}; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+14); .if((poi(@esp+14)&0x0`F0000000)=0x0`F0000000){.echo CRYPT_VERIFYCONTEXT(0xf0000000)}; .if((poi(@esp+14)&0x0`00000008)=0x0`00000008){.echo CRYPT_NEWKEYSET(0x8)}; .if((poi(@esp+14)&0x0`00000010)=0x0`00000010) {.echo CRYPT_DELETEKEYSET(0x10)}; .if((poi(@esp+14)&0x0`00000020)=0x0`00000020) {.echo CRYPT_MACHINE_KEYSET(0x20)}; .if((poi(@esp+14)&0x0`00000040)=0x0`00000040) {.echo CRYPT_SILENT(0x40)}; bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if(poi(@esp-14)=0) {.echo phProv;.echo NULL} .else {.echo hProv; .if(poi(poi(@esp-14))=0) {.echo NULL} .else {.printf \\\"%#x\\\\n\\\", poi(poi(@esp-14))} }; .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptAcquireContextA (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptAcquireContextA (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptGetProvParam ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptGetProvParam (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hProv\\n%#x\\n\\n\", poi(@esp+4); .echo dwParam; .if(poi(@esp+8)=0x16) {.echo PP_ENUMALGS_EX} .else {.printf \"%#x\\n\", poi(@esp+8)}; .echo;.echo pbData; .if(poi(@esp+c)=0) {.echo NULL} .else {.printf \"%#x\\n\", poi(@esp+c)}; .printf \"\\ndwDataLen\\n%d\\n\", poi(poi(@esp+10)); .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+14); bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if((poi(@esp-c)!=0) & (poi(poi(@esp-8))!=0)) {r $t0=(poi(poi(@esp-8))+3)/4; .echo bData; dd poi(@esp-c) l@$t0; .echo}; .printf \\\"dwDataLen\\\\n%d\\\\n\\\", poi(poi(@esp-8)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptGetProvParam (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptGetProvParam (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptGenRandom ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptGenRandom (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hProv\\n%#x\\n\\n\", poi(@esp+4); .printf \"dwLen\\n%d\\n\", poi(@esp+8); r $t0=(poi(@esp+8)+3)/4; .echo;.echo bBuffer; dd poi(@esp+c) l@$t0; bp /t @$thread poi(@esp) \" .echo;.echo OUT; r $t0=(poi(@esp-8)+3)/4; .echo bBuffer; dd poi(@esp-4) l@$t0; .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptGenRandom (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptGenRandom (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptReleaseContext ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptReleaseContext (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hProv\\n%#x\\n\\n\", poi(@esp+4); .printf \"dwFlags\\n%#x\\n\", poi(@esp+8); bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptReleaseContext (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptReleaseContext (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptCreateHash ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptCreateHash (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hProv\\n%#x\\n\\n\", poi(@esp+4); .echo Algid; .if(poi(@esp+8)=0x00008004) {.echo CALG_SHA} .elsif(poi(@esp+8)=0x00008003) {.echo CALG_MD5} .else {.printf \"%#x\\n\", poi(@esp+8)}; .printf \"\\nhKey\\n%#x\\n\\n\", poi(@esp+c); .printf \"dwFlags\\n%#x\\n\", poi(@esp+10); bp /t @$thread poi(@esp) \" .echo;.echo OUT; .printf \\\"hHash\\\\n%#x\\\\n\\\", poi(poi(@esp-4)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptCreateHash (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptCreateHash (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptHashData ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptHashData (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hHash\\n%#x\\n\\n\", poi(@esp+4); r $t0=(poi(@esp+c)+3)/4; .echo bData;dd poi(@esp+8) l@$t0; .printf \"\\ndwDataLen\\n%d\\n\\n\", poi(@esp+c); .printf \"dwFlags\\n%#x\\n\", poi(@esp+10); bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptHashData (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptHashData (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptDestroyHash ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptDestroyHash (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hHash\\n%#x\\n\", poi(@esp+4); bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptDestroyHash (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptDestroyHash (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptGetHashParam ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptGetHashParam (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hHash\\n%#x\\n\", poi(@esp+4); .echo;.echo dwParam; .if(poi(@esp+8)=0x1) {.echo HP_ALGID} .elsif(poi(@esp+8)=0x2) {.echo HP_HASHVAL} .elsif(poi(@esp+8)=0x4) {.echo HP_HASHSIZE} .else {.printf \"%#x\\n\", poi(@esp+8)}; .echo;.echo pbData; .if(poi(@esp+c)=0) {.echo NULL} .else {.printf \"%#x\\n\", poi(@esp+c)}; .printf \"\\ndwDataLen\\n%d\\n\", poi(poi(@esp+10)); .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+14); bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if((poi(@esp-c)!=0) & (poi(poi(@esp-8))!=0)) {r $t0=(poi(poi(@esp-8))+3)/4; .echo bData; dd poi(@esp-c) l@$t0; .echo}; .printf \\\"dwDataLen\\\\n%d\\\\n\\\", poi(poi(@esp-8)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptGetHashParam (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptGetHashParam (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptGetUserKey ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptGetUserKey (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hProv\\n%#x\\n\\n\", poi(@esp+4); .echo dwKeySpec; .if(poi(@esp+8)=0x1) {.echo AT_KEYEXCHANGE} .elsif(poi(@esp+8)=0x2) {.echo AT_SIGNATURE} .else {.printf \"%#x\\n\", poi(@esp+8)}; bp /t @$thread poi(@esp) \" .echo;.echo OUT; .printf \\\"hUserKey\\\\n%#x\\\\n\\\", poi(poi(@esp-4)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptGetUserKey (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptGetUserKey (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptGenKey ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptGenKey (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hProv\\n%#x\\n\\n\", poi(@esp+4); .echo Algid; .if(poi(@esp+8)=0x1) {.echo AT_KEYEXCHANGE} .elsif(poi(@esp+8)=0x2) {.echo AT_SIGNATURE} .elsif(poi(@esp+8)=0x00008004) {.echo CALG_SHA} .else {.printf \"%#x\\n\", poi(@esp+8)}; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+c); r $t0=(poi(@esp+c))>>10; .printf \"Key Size(%d)\\n\", @$t0; .if((poi(@esp+c)&0x0`00000001)=0x0`00000001) {.echo CRYPT_EXPORTABLE(0x1)}; bp /t @$thread poi(@esp) \" .echo;.echo OUT; .printf \\\"hKey\\\\n%#x\\\\n\\\", poi(poi(@esp-4)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptGenKey (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptGenKey (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptGetKeyParam ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptGetKeyParam (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hKey\\n%#x\\n\\n\", poi(@esp+4); .echo dwParam; .if(poi(@esp+8)=0x7) {.echo KP_ALGID} .elsif(poi(@esp+8)=0x9) {.echo KP_KEYLEN} .else {.printf \"%#x\\n\", poi(@esp+8)}; .echo;.echo pbData; .if(poi(@esp+c)=0) {.echo NULL} .else {.printf \"%#x\\n\", poi(@esp+c)}; .printf \"\\ndwDataLen\\n%d\\n\", poi(poi(@esp+10)); .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+14); bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if((poi(@esp-c)!=0) & (poi(poi(@esp-8))!=0)) {r $t0=(poi(poi(@esp-8))+3)/4; .echo bData; dd poi(@esp-c) l@$t0; .echo}; .printf \\\"dwDataLen\\\\n%d\\\\n\\\", poi(poi(@esp-8)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptGetKeyParam (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptGetKeyParam (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptDestroyKey ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptDestroyKey (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hKey\\n%#x\\n\", poi(@esp+4); bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptDestroyKey (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptDestroyKey (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptEncrypt ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptEncrypt (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hKey\\n%#x\\n\\n\", poi(@esp+4); .printf \"hHash\\n%#x\\n\\n\", poi(@esp+8); .echo Final; .if(poi(@esp+c)=0) {.echo FALSE} .else {.echo TRUE}; .echo;.echo dwFlags; .if(poi(@esp+10)=0x40) {.echo CRYPT_OAEP} .else {.printf \"%#x\\n\", poi(@esp+10)}; .echo; .if((poi(@esp+14)!=0) & (poi(poi(@esp+18))!=0)) {r $t0=(poi(poi(@esp+18))+3)/4; .echo bData; dd poi(@esp+14) l@$t0} .elsif(poi(@esp+14)=0) {.echo pbData;.echo NULL} .else {.printf \"pbData\\n%#x\\n\", poi(@esp+14)}; .echo; .printf \"dwDataLen\\n%d\\n\\n\", poi(poi(@esp+18)); .printf \"dwBufLen\\n%d\\n\", poi(@esp+1c); bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if((poi(@esp-c)!=0) & (poi(poi(@esp-8))!=0)) {r $t0=(poi(poi(@esp-8))+3)/4; .echo bData; dd poi(@esp-c) l@$t0; .echo}; .printf \\\"dwDataLen\\\\n%d\\\\n\\\", poi(poi(@esp-8)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptEncrypt (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptEncrypt (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptDecrypt ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptDecrypt (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hKey\\n%#x\\n\\n\", poi(@esp+4); .printf \"hHash\\n%#x\\n\\n\", poi(@esp+8); .echo Final; .if(poi(@esp+c)=0) {.echo FALSE} .else {.echo TRUE}; .echo;.echo dwFlags; .if(poi(@esp+10)=0x40) {.echo CRYPT_OAEP} .else {.printf \"%#x\\n\", poi(@esp+10)}; .echo; .if((poi(@esp+14)!=0) & (poi(poi(@esp+18))!=0)) {r $t0=(poi(poi(@esp+18))+3)/4; .echo bData; dd poi(@esp+14) l@$t0; .echo} .elsif(poi(@esp+14)=0) {.echo pbData;.echo NULL;.echo}; .printf \"dwDataLen\\n%d\\n\\n\", poi(poi(@esp+18)); bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if((poi(@esp-8)!=0) & (poi(poi(@esp-4))!=0)) {r $t0=(poi(poi(@esp-4))+3)/4; .echo bData; dd poi(@esp-8) l@$t0; .echo}; .printf \\\"dwDataLen\\\\n%d\\\\n\\\", poi(poi(@esp-4)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptDecrypt (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptDecrypt (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptSetHashParam ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptSetHashParam (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hHash\\n%#x\\n\", poi(@esp+4); .echo;.echo dwParam; .if(poi(@esp+8)=0x2) {.echo HP_HASHVAL} .elsif(poi(@esp+8)=0x5) {.echo HP_HMAC_INFO} .else {.printf \"%#x\\n\", poi(@esp+8)}; .echo; .if(poi(@esp+c)=0) {.echo pbData;.echo NULL} .else {.echo bData;dd poi(@esp+c)}; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+10); bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptSetHashParam (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptSetHashParam (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptSignHashW ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\CryptSignHashW (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hHash\\n%#x\\n\", poi(@esp+4); .echo;.echo dwKeySpec; .if (poi(@esp+8)=0x1) {.echo AT_KEYEXCHANGE} .elsif (poi(@esp+8)=0x2) {.echo AT_SIGNATURE} .else {.printf \"%#x\\n\", poi(@esp+8)}; .echo;.echo sDescription; .if (poi(@esp+c)=0) {.echo NULL} .else {du poi(@esp+c)}; .printf \"dwFlags\\n%#x\\n\", poi(@esp+10); .echo;.echo pbSignature; .if (poi(@esp+14)=0) {.echo NULL} .else {.printf \"%#x\\n\", poi(@esp+14)}; .printf \"\\ndwSigLen\\n%d\\n\", poi(poi(@esp+18)); bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if((poi(@esp-8)!=0) & (poi(poi(@esp-4))!=0)) {r $t0=(poi(poi(@esp-4))+3)/4; .echo bSignature; dd poi(@esp-8) l@$t0; .echo}; .printf \\\"dwSigLen\\\\n%d\\\\n\\\", poi(poi(@esp-4)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptSignHashW (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptSignHashW (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptSignHashA ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptSignHashA (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hHash\\n%#x\\n\", poi(@esp+4); .echo;.echo dwKeySpec; .if (poi(@esp+8)=0x1) {.echo AT_KEYEXCHANGE} .elsif (poi(@esp+8)=0x2) {.echo AT_SIGNATURE} .else {.printf \"%#x\\n\", poi(@esp+8)}; .echo;.echo sDescription; .if (poi(@esp+c)=0) {.echo NULL} .else {da poi(@esp+c)}; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+10); .echo;.echo pbSignature; .if (poi(@esp+14)=0) {.echo NULL} .else {.printf \"%#x\\n\", poi(@esp+14)}; .printf \"\\ndwSigLen\\n%d\\n\", poi(poi(@esp+18)); bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if((poi(@esp-8)!=0) & (poi(poi(@esp-4))!=0)) {r $t0=(poi(poi(@esp-4))+3)/4; .echo bSignature; dd poi(@esp-8) l@$t0; .echo}; .printf \\\"dwSigLen\\\\n%d\\\\n\\\", poi(poi(@esp-4)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptSignHashA (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptSignHashA (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptVerifySignatureW ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptVerifySignatureW (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hHash\\n%#x\\n\\n\", poi(@esp+4); .if((poi(@esp+8)!=0) & (poi(@esp+c)!=0)) {r $t0=(poi(@esp+c)+3)/4; .echo bSignature; dd poi(@esp+8) l@$t0;} .elsif(poi(@esp+8)=0) {.echo pbSignature;.echo NULL;} .else {.printf \"pbSignature\\n%#x\\n\", poi(@esp+8)}; .printf \"\\ndwSigLen\\n%d\\n\\n\", poi(@esp+c); .printf \"hPubKey\\n%#x\\n\", poi(@esp+10); .echo;.echo sDescription; .if (poi(@esp+14)=0) {.echo NULL} .else {du poi(@esp+14)}; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+18); bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptVerifySignatureW (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptVerifySignatureW (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptVerifySignatureA ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptVerifySignatureA (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hHash\\n%#x\\n\\n\", poi(@esp+4); .if((poi(@esp+8)!=0) & (poi(@esp+c)!=0)) {r $t0=(poi(@esp+c)+3)/4; .echo bSignature; dd poi(@esp+8) l@$t0;} .elsif(poi(@esp+8)=0) {.echo pbSignature;.echo NULL;} .else {.printf \"pbSignature\\n%#x\\n\", poi(@esp+8)}; .printf \"\\ndwSigLen\\n%d\\n\\n\", poi(@esp+c); .printf \"hPubKey\\n%#x\\n\", poi(@esp+10); .echo;.echo sDescription; .if (poi(@esp+14)=0) {.echo NULL} .else {da poi(@esp+14)}; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+18); bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptVerifySignatureA (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptVerifySignatureA (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptImportKey ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptImportKey (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hProv\\n%#x\\n\\n\", poi(@esp+4); .if((poi(@esp+8)!=0) & (poi(@esp+c)!=0)) {r $t0=(poi(@esp+c)+3)/4; .echo bData; dd poi(@esp+8) l@$t0;} .elsif(poi(@esp+8)=0) {.echo pbData;.echo NULL;} .else {.printf \"pbData\\n%#x\\n\", poi(@esp+8)}; .printf \"\\ndwDataLen\\n%d\\n\\n\", poi(@esp+c); .printf \"hPubKey\\n%#x\\n\\n\", poi(@esp+10); .printf \"dwFlags\\n%#x\\n\", poi(@esp+14); .if((poi(@esp+14)&0x0`00000001)=0x0`00000001) {.echo CRYPT_EXPORTABLE(0x1)}; bp /t @$thread poi(@esp) \" .echo;.echo OUT; .printf \\\"hKey\\\\n%#x\\\\n\\\", poi(poi(@esp-4)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptImportKey (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptImportKey (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Advapi32!CryptExportKey ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptExportKey (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"hKey\\n%#x\\n\\n\", poi(@esp+4); .printf \"hExpKey\\n%#x\\n\\n\", poi(@esp+8); .echo dwBlobType; .if(poi(@esp+c)=0x7) {.echo PRIVATEKEYBLOB} .else {.printf \"%#x\\n\", poi(@esp+c)}; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+10); .if((poi(@esp+10)&0x0`00000040)=0x0`00000040) {.echo CRYPT_OAEP(0x40)}; .echo;.echo pbData; .if(poi(@esp+14)=0) {.echo NULL} .else {.printf \"%#x\\n\", poi(@esp+14)}; .printf \"\\ndwDataLen\\n%d\\n\", poi(poi(@esp+18)); bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if((poi(@esp-8)!=0) & (poi(poi(@esp-4))!=0)) {r $t0=(poi(poi(@esp-4))+3)/4; .echo bData; dd poi(@esp-8) l@$t0; .echo}; .printf \\\"dwDataLen\\\\n%d\\\\n\\\", poi(poi(@esp-4)); .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptExportKey (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptExportKey (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

************************************************************************
* CRYPT32!CRYPT* TRACERS
************************************************************************

bm Crypt32!CryptProtectData ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptProtectData (%#x)\\n\", @$tid; .echo;.echo IN; .if (poi(@esp+4)=0) {.echo pDataIn;.echo NULL} .else {.printf \"pDataIn->cbData\\n%d\\n\\n\", poi(poi(@esp+4)); r $t0=(poi(poi(@esp+4))+3)/4;.if(@$t0 > 40){r $t0=40}; .echo pDataIn->pbData;dd poi(poi(@esp+4)+4) l@$t0}; .echo;.echo szDataDescr; .if(poi(@esp+8)=0) {.echo NULL} .else {du poi(@esp+8)}; .echo; .if (poi(@esp+c)=0) {.echo pOptionalEntropy;.echo NULL} .else { .printf \"pOptionalEntropy->cbData\\n%d\\n\", poi(poi(@esp+c)); r $t0=(poi(poi(@esp+c))+3)/4;.if(@$t0 > 40){r $t0=40}; .echo;.echo pOptionalEntropy->pbData;dd poi(poi(@esp+c)+4) l@$t0}; .echo;.echo vReserved; .if (poi(@esp+10)=0) {.echo NULL} .else {.printf\"%#x\\n\", poi(@esp+10)}; .echo; .if (poi(@esp+14)=0) {.echo pPromptStruct;.echo NULL} .else {.printf \"pPromptStruct->cbSize\\n%d\\n\\n\", poi(poi(@esp+14)); .printf \"pPromptStruct->dwPromptFlags\\n%#x\\n\", poi(poi(@esp+14)+4); .if((poi(poi(@esp+14)+4)&0x0`00000001)=0x0`00000001) {.echo CRYPTPROTECT_PROMPT_ON_UNPROTECT(0x1)}; .if((poi(poi(@esp+14)+4)&0x0`00000002)=0x0`00000002) {.echo CRYPTPROTECT_PROMPT_ON_PROTECT(0x2)}; .printf \"\\npPromptStruct->hwndApp\\n%#x\\n\\n\", poi(poi(@esp+14)+8); .echo pPromptStruct->szPrompt; .if(poi(poi(@esp+14)+c)=0) {.echo NULL} .else {du poi(poi(@esp+14)+c)} }; .echo; .printf \"dwFlags\\n%#x\\n\", poi(@esp+18); .if((poi(@esp+18)&0x0`00000004)=0x0`00000004) {.echo CRYPTPROTECT_LOCAL_MACHINE(0x4)}; .if((poi(@esp+18)&0x0`00000001)=0x0`00000001) {.echo CRYPTPROTECT_UI_FORBIDDEN(0x1)}; .if((poi(@esp+18)&0x0`00000010)=0x0`00000010) {.echo CRYPTPROTECT_AUDIT(0x10)}; .if((poi(@esp+18)&0x0`00000040)=0x0`00000040) {.echo CRYPTPROTECT_VERIFY_PROTECTION(0x40)}; bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if (poi(@esp-4)=0) {.echo pDataOut;.echo NULL} .else {.printf \\\"pDataOut->cbData\\\\n%d\\\\n\\\", poi(poi(@esp-4)); r $t0=(poi(poi(@esp-4))+3)/4;.if(@$t0 > 40){r $t0=40}; .echo;.echo pDataOut->pbData;dd poi(poi(@esp-4)+4) l@$t0}; .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptProtectData (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptProtectData (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Crypt32!CryptUnprotectData ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptUnprotectData (%#x)\\n\", @$tid; .echo;.echo IN; .if (poi(@esp+4)=0) {.echo pDataIn;.echo NULL} .else {.printf \"pDataIn->cbData\\n%d\\n\\n\", poi(poi(@esp+4)); r $t0=(poi(poi(@esp+4))+3)/4;.if(@$t0 > 40){r $t0=40}; .echo pDataIn->pbData;dd poi(poi(@esp+4)+4) l@$t0}; .echo; .if (poi(@esp+c)=0) {.echo pOptionalEntropy;.echo NULL} .else { .printf \"pOptionalEntropy->cbData\\n%d\\n\", poi(poi(@esp+c)); r $t0=(poi(poi(@esp+c))+3)/4;.if(@$t0 > 40){r $t0=40}; .echo;.echo pOptionalEntropy->pbData;dd poi(poi(@esp+c)+4) l@$t0}; .echo;.echo vReserved; .if (poi(@esp+10)=0) {.echo NULL} .else {.printf\"%#x\\n\", poi(@esp+10)}; .echo; .if (poi(@esp+14)=0) {.echo pPromptStruct;.echo NULL} .else {.printf \"pPromptStruct->cbSize\\n%d\\n\\n\", poi(poi(@esp+14)); .printf \"pPromptStruct->dwPromptFlags\\n%#x\\n\", poi(poi(@esp+14)+4); .if((poi(poi(@esp+14)+4)&0x0`00000001)=0x0`00000001) {.echo CRYPTPROTECT_PROMPT_ON_UNPROTECT(0x1)}; .if((poi(poi(@esp+14)+4)&0x0`00000002)=0x0`00000002) {.echo CRYPTPROTECT_PROMPT_ON_PROTECT(0x2)}; .printf \"\\npPromptStruct->hwndApp\\n%#x\\n\\n\", poi(poi(@esp+14)+8); .echo pPromptStruct->szPrompt; .if(poi(poi(@esp+14)+c)=0) {.echo NULL} .else {du poi(poi(@esp+14)+c)} }; .echo; .printf \"dwFlags\\n%#x\\n\", poi(@esp+18); .if((poi(@esp+18)&0x0`00000001)=0x0`00000001) {.echo CRYPTPROTECT_UI_FORBIDDEN(0x1)}; bp /t @$thread poi(@esp) \" .echo;.echo OUT; .if(poi(@esp-18)=0) {.echo ppszDataDescr;.echo NULL} .else {.echo szDataDescr; .if(poi(poi(@esp-18))=0) {.echo NULL} .else {du poi(poi(@esp-18))} }; .echo; .if (poi(@esp-4)=0) {.echo pDataOut;.echo NULL} .else {.printf \\\"pDataOut->cbData\\\\n%d\\\\n\\\", poi(poi(@esp-4)); r $t0=(poi(poi(@esp-4))+3)/4;.if(@$t0 > 40){r $t0=40}; .echo;.echo pDataOut->pbData;dd poi(poi(@esp-4)+4) l@$t0}; .echo;.echo RESULT; .if(@eax=1) {.printf \\\"CryptUnprotectData (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptUnprotectData (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Crypt32!CryptMemAlloc ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptMemAlloc (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"cbSize\\n%d\\n\", poi(@esp+4); bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .printf \\\"%#x\\\\n\\\\n\\\", @eax; .if(@eax!=0) {.printf \\\"CryptMemAlloc (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptMemAlloc (%#x) FAILED\\\\n\\\", @$tid;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

bm Crypt32!CryptMemFree ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCryptMemFree (%#x)\\n\", @$tid; .echo;.echo IN; .printf \"pv\\n%#x\\n\", poi(@esp+4); bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .printf \\\"CryptMemFree (%#x) SUCCEEDED\\\\n\\\", @$tid; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

************************************************************************
* CRYPT32!CERT* TRACERS
************************************************************************

bm Crypt32!CertOpenStore ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\nCertOpenStore (%#x)\\n\", @$tid; .echo;.echo IN; .echo lpszStoreProvider; .if(poi(@esp+4)=0) {.echo NULL} .elsif(poi(@esp+4)=0x1) {.echo CERT_STORE_PROV_MSG} .elsif(poi(@esp+4)=0x2) {.echo CERT_STORE_PROV_MEMORY} .elsif(poi(@esp+4)=0xa) {.echo CERT_STORE_PROV_SYSTEM_W} .elsif(poi(@esp+4)=0xb) {.echo CERT_STORE_PROV_COLLECTION} .elsif(poi(@esp+4)=0xd) {.echo CERT_STORE_PROV_SYSTEM_REGISTRYW} .else {da poi(@esp+4)}; .echo; .printf \"dwMsgAndCertEncodingType\\n%#x\\n\", poi(@esp+8); .if((poi(@esp+8)&0x0`00000001)=0x0`00000001) {.echo X509_ASN_ENCODING(0x1)}; .if((poi(@esp+8)&0x0`00010000)=0x0`00010000) {.echo PKCS_7_ASN_ENCODING(0x10000)}; .echo; .echo hCryptProv; .if(poi(@esp+c)=0) {.echo NULL} .else {.printf \"%#x\\n\", poi(@esp+c)}; .echo; .printf \"dwFlags\\n%#x\\n\", poi(@esp+10); .if((poi(@esp+10)&0x0`00000001)=0x0`00000001) {.echo CERT_STORE_NO_CRYPT_RELEASE_FLAG(0x1)}; .if((poi(@esp+10)&0x0`00000004)=0x0`00000004) {.echo CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG(0x4)}; .if((poi(@esp+10)&0x0`00000080)=0x0`00000080) {.echo CERT_STORE_SHARE_CONTEXT_FLAG(0x80)}; .if((poi(@esp+10)&0x0`00000400)=0x0`00000400) {.echo CERT_STORE_UPDATE_KEYID_FLAG(0x400)}; .if((poi(@esp+10)&0x0`00001000)=0x0`00001000) {.echo CERT_STORE_MAXIMUM_ALLOWED_FLAG(0x1000)}; .if((poi(@esp+10)&0x0`FFFF0000)=0x0`00010000) {.echo CERT_SYSTEM_STORE_CURRENT_USER(0x10000)} .elsif((poi(@esp+10)&0x0`FFFF0000)=0x0`00020000) {.echo CERT_SYSTEM_STORE_LOCAL_MACHINE(0x20000)} .elsif((poi(@esp+10)&0x0`FFFF0000)=0x0`00040000) {.echo CERT_SYSTEM_STORE_CURRENT_SERVICE(0x40000)} .elsif((poi(@esp+10)&0x0`FFFF0000)=0x0`00050000) {.echo CERT_SYSTEM_STORE_SERVICES(0x50000)} .elsif((poi(@esp+10)&0x0`FFFF0000)=0x0`00060000) {.echo CERT_SYSTEM_STORE_USERS(0x60000)} .elsif((poi(@esp+10)&0x0`FFFF0000)=0x0`00070000) {.echo CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY(0x70000)} .elsif((poi(@esp+10)&0x0`FFFF0000)=0x0`00080000) {.echo CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY(0x80000)} .elsif((poi(@esp+10)&0x0`FFFF0000)=0x0`00090000) {.echo CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE(0x90000)}; .echo; .if(poi(@esp+14)=0) {.echo pvPara; .echo NULL} .else {.echo vPara; dd poi(@esp+14)}; bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .if(@eax!=0) {.printf \\\"%#x\\\\n\\\\nCertOpenStore (%#x) SUCCEEDED\\\\n\\\", @eax, @$tid;} .else {.printf \\\"NULL\\\\n\\\\nCertOpenStore (%#x) FAILED\\\\n\\\", @$tid; !gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";

************************************************************************
* LET'S GO AND TRACE!!!
************************************************************************

* Don't want any output but my own
*
!sym quiet;
.srcnoisy 0;
sxi ld
.outmask- 0xFFFFFFEE $$ .outmask /d restores the output mask to default

* Create the log and begin
*
.logopen "log.txt";
G



I hope it helps you as much as it helps me every day.


Cheers,



Alex (Alejandro Campos Magencio)



PS: If you find any issue with the script, please let me know so I can improve it. Obviously I couldn't test it in all possible scenarios.For instance, if the debugger breaks on an exception (i.e. Access Violation), the tracing will break, too. We will have to make the tracer to continue with the "g" command in the debugger.


PS: More explanations on this script can be found in my next post How to trace CryptoAPI calls (2).


Original URL: https://blogs.msdn.microsoft.com/alejacma/2007/10/29/how-to-trace-cryptoapi-calls/
Post name: How to trace CryptoAPI calls
Original author: Alejandro Campos Magencio
Posting date: 2007-10-29T07:42:00+00:00


Hi, welcome back,


An application may use CryptoAPI without us developers realizing it. Security classes in .NET Framework use CryptoAPI behind the scenes. CAPICOM.dll uses it, too.


The issue appears when the API returns an error which can help us to find the real cause of the issue, but the code calling it captures the error and returns a completely different one which won't help us at all. Remember for instance my previous post,RSACryptoServiceProvider fails when used with mandatory profiles, where .NET was returning "Cryptographic Service Provider (CSP) for this implementation could not be acquired" but the real error was being returned by CryptAcquireContext: NTE_TEMPORARY_PROFILE. With .NET's error I don't know what's going on. With CryptAcquireContext's I do know.


Fortunatelydebuggers like Windbg.exe\Cdb.exe(part of our Debugging Tools for Windows) are very handy here. If we want to trace the calls that an application is making to CryptoAPI behind the scenes, we can follow these steps:


1) Attach Windbg or Cdb (command line version of Windbg) to the desired process.


2) Set the following breakpoint:


bm Advapi32!Crypt* ".printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\n(%#x)\\n\\n\", @$tid; .echo CALL;k 1; bp /t @$thread poi(@esp) \" .echo;.echo RESULT; .if(@eax=1) {.echo SUCCEEDED} .else {.echo FAILED;!gle}; .echo;.echo <<<<<<<<<<<<<<<<<<<<<<; G;\"; G;";


Note: There are other Crypt* APIs on Crypt32.dll, so an additional breakpoint may be set for them.


3) Continue running the application under the control of the debugger.



Whatis that "bm" command doing exactly? It will be easier to understand it if I write it this way:

00  bm Advapi32!Crypt*
01 "
02 .printf \"\\n>>>>>>>>>>>>>>>>>>>>>>\\n\\n(%#x)\\n\\n\", @$tid;
03
04 .echo CALL;
05 k 1;
06
07 bp /t @$thread poi(@esp)
08 \"
09 .echo;
10 .echo RESULT;
11
12 .if(@eax=1)
13 {
14 .echo SUCCEEDED
15 }
16 .else
17 {
18 .echo FAILED;
19 !gle
20 };
21
22 .echo;
23 .echo <<<<<<<<<<<<<<<<<<<<<<;
24
25 G;
26 \";
27
28 G;
29 ";

00) We set a breakpoint on all APIs found in Advapi32.dll which start by "Crypt". The following commands will be executed when the application calls any of those APIs thus reaching any of those breakpoints:


02) We print the id of the thread calling the API ("$tid" pseudo-register). ".printf" works pretty much the same way as our old friend "printf" in C. Instead of ' " 'and ' \n ' we will have to use ' \" 'and ' \\n ', becausethese commands are already between' " '.


04) We print the string "CALL" with ".echo".


05) We print the first line of the call stack gotten when the breakpoint is reached ("k 1"). The API we are calling will correspond to that first line. Here we could show the parameters being passed to the API by using "kp" command(if we have symbols -.pdb files- associated to Advapi32.dll), or any other way.


07) Now we want to know what happened after the API finished executing. When we stop on the breakpoint set at 00, the "esp" register (stack pointer)points to the return address where we will go after the call to the API ends. So we set a breakpoint at that address with "bp". And if we don't want weird things to happen on multi-threaded applications, we have to specify on which thread ("$thread" pseudo-register)we are setting that breakpoint.


28) Once we've set the breakpoint at 07, we can continue the execution of the application with "g" command.


Now, let see what happens when we stop onbreakpoint setat 07:


09 & 10) We print the string "RESULT".


12) When the API has finished executing, its return value will be stored in the "eax" register. The Crypt* functions in Advapi32 will return 1 if they succeed or 0 if they don't. We use ".if {} .else {}" command to determine which one we got.


14) The API succeeded, so we print the string "SUCCEEDED".


18 & 19) The APIfailed, so we print the string "FAILED" and show the last error value with "!gle" (Get Last Error) command.


25) Now that we know the result of calling the API, we can continue the execution of the application and trace more APIs.



Comments on this:


- Some people may think that setting a breakpoint at 07 is unnecessary, as we could use "gu" command to get to the end of the call instead. But if we use "gu" and a CryptoAPI calls another one, we will miss the return value of the former.


- I tried setting the breakpoint at 07 using "~~[$tid] bp ...", but the behavior wasn't correct. I don't know why the debugger was stopping several times on the same breakpoint instead of just one. Using "bp /t @$thread ..." instead worked just fine.



Ihope this helps.


Cheers,



Alex (Alejandro Campos Magencio)



PS: I'm currently developing a Windbg\Cdb script based on the principles explained in this post which traces all CryptoAPI calls, but this time showing all their in & out parameters in a very user friendly way. You can see its current version here.

Original URL: https://blogs.msdn.microsoft.com/alejacma/2007/10/23/rsacryptoserviceprovider-fails-when-used-with-mandatory-profiles/
Post name: RSACryptoServiceProvider fails when used with mandatory profiles
Original author: Alejandro Campos Magencio
Posting date: 2007-10-23T06:27:00+00:00


Hi, welcome back,

I will talk today about a very common issue we face when we try to use .NET's RSACryptoServiceProvider (http://msdn2.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx)class with mandatory profiles (i.e. Citrix environment).

When we try to create a new RSACryptoServiceProvider object in this scenario, we get the following exception:

"System.Security.Cryptography.CryptographicException: Cryptographic Service Provider (CSP) for this implementation could not be acquired".

This behavior is by design for security protection.

RSACryptoServiceProvider calls CryptAcquireContext API (http://msdn2.microsoft.com/en-us/library/aa379886.aspx) behind the scenes to get a handle to a key container within a CSP (Cryptographic Service Provider). CryptAcquireContext will fail with NTE_TEMPORARY_PROFILE error when called from a mandatory profile.

Mandatory profiles are read-only user profiles. Since changes to the mandatory profile cannot be saved, PKI design doesn't allow this operation, and CryptAcquireContext prevents this scenario by failing.

Private keys are protected by DPAPI (Data Protection API) component of Windows. DPAPI component regularly creates new Master Keys in the profile to protect confidential information such as private keys. For security reasons, Master Keys will expire, which means that after a period of time, the hard-coded value being three months, a new Master Key is generated and protected in the same manner. This expiration prevents an attacker from compromising a single Master Key and accessing all of a user's protected data.

The Master Key regeneration is explained in the DPAPI white-paper at:

Windows Data Protection
http://msdn2.microsoft.com/en-us/library/ms995355.aspx

So, higher level components that depend on DPAPI to protect confidential information cannot be protected securely with read-only profiles.

More information about all this can be found here:

Cryptographic Keys and Certificates Cannot Be Used with Mandatory Profiles
http://support.microsoft.com/default.aspx?scid=kb;en-us;264732

How to troubleshoot the Data Protection API (DPAPI)
"DPAPI and Mandatory Profiles"
http://support.microsoft.com/default.aspx?scid=kb;en-us;309408

Cannot Gain Access to Microsoft Encrypted File Systems
http://support.microsoft.com/kb/243850/en-us


There are three possible solutions to this issue:

1)If you need to access some user’s private keys (i.e. when signing data) and you want to prevent other users from using its keys, the only way is configuring the profile as non-mandatory.

2)If you need a persistent RSA private key, then the only solution is to use CryptAcquireContext with the CRYPT_MACHINE_KEYSET flag (or RSACryptoServiceProvider with the CspProviderFlags.UseMachineKeyStore flag) for private key storage in this configuration. But this is not protected based on the user's password hash, so any user with access to the machine may have access to those keys.

3)If you don’t need persistent RSA private keys (i.e. when verifying signatures), you could use CryptAcquireContext with the CRYPT_VERIFYCONTEXT flag. This flag tells CryptoAPI to create the key container in memory and not in the user’s profile. And you won't need to worry about deleting the key container; you just release the handle with CryptReleaseContext (http://msdn2.microsoft.com/en-us/library/aa380268.aspx).

Additional info about CryptAcquireContext & CRYPT_VERIFYCONTEXT can be found here:

238187 CryptAcquireContext() use and troubleshooting
http://support.microsoft.com/?id=238187

The problem is that, at the moment of this writing,creating a temporary key container with RSACryptoServiceProvider is not possible. We may think of using CryptAcquireContextwith CRYPT_VERIFYCONTEXT flag to get a handle to the key container within the CSP before using RSACryptoServiceProvider, but RSACryptoServiceProvider maintains its own cryptographic handle and it's not possible to give RSACryptoServiceProvider a handle to use. We have already requested .NET Framework developers to expose CRYPT_VERIFYCONTEXT for us, but I can't tell when we will get such a feature.

The way to i.e. verify signatures using temporary keysets in .NET would be to use CryptoAPI directly through P/Invoke (Platform Invoke), instead of using RSACryptoServiceProvider.

I hope this helps.

Cheers,

Alex (Alejandro Campos Magencio)

PS: In a near future I will post how we can easily see which CryptoAPI calls .NET is making behind the scenes. When a CryptoAPI call fails, .NET captures the error and it returns its own exception, which is not always self-explanatory as we've seen today. We will be able to see the failing CryptoAPI, and which error is actually returning. This way, if we see a "Cryptographic Service Provider (CSP) for this implementation could not be acquired" error, we will be able to see for instancethat CryptAcquireContext is failing with NTE_TEMPORARY_PROFILE and that will give us some clues about what's going on there.

Original URL: https://blogs.msdn.microsoft.com/alejacma/2007/10/19/capicom-support-on-windows-vista/
Post name: CAPICOM support on Windows Vista
Original author: Alejandro Campos Magencio
Posting date: 2007-10-19T03:47:00+00:00


I know there has been a lot of confusion about this, because some articles on the web (i.e. MSDN) say CAPICOM is not supported on Vista, while others say it is.

I have good news for you people, especially for those who want to do cryptographic operations from scripting: CAPICOM is officially supported on Vista, but only on its version 2.1.0.2.

This version can be downloaded from here:

Platform SDK Redistributable: CAPICOM
http://www.microsoft.com/downloads/details.aspx?FamilyID=860ee43a-a843-462f-abb5-ff88ea5896f6&DisplayLang=en

(Note: at the time of this writing, this article DOES NOT say that CAPICOM is supported on Vista).

This new version of CAPICOM was released, among other reasons,because of a security update on CAPICOM:

Security Update for CAPICOM (KB931906)
http://www.microsoft.com/downloads/details.aspx?FamilyId=CA930018-4A66-4DA6-A6C5-206DF13AF316&displaylang=en

(Note: this article DOES say that CAPICOM is supported on Vista)

If we try to use version 2.1.0.1 on Vista, for instance,a small .NET sample which uses CAPICOM like the following:
"
StoreClass store = new StoreClass();
store.Open(CAPICOM_STORE_LOCATION.CAPICOM_SMART_CARD_USER_STORE, null, CAPICOM_STORE_OPEN_MODE.CAPICOM_STORE_OPEN_READ_WRITE);

"
Will return the following exception:
"
System.Runtime.InteropServices.COMException (0x80880900): Exception from HRESULT: 0x80880900
"
Which means:
"
# for hex 0x80880900 / decimal -2138568448
CAPICOM_E_NOT_SUPPORTED capicom.h

"

Anyway, my recommendation is to use .NET Framework classes instead of CAPICOM whenever possible.

I hope this helps.

Cheers,

Alex (Alejandro Campos Magencio)