microsoft / DTrace-on-Windows

Code for the cross platform, single source, OpenDTrace implementation
Other
473 stars 42 forks source link

printf widestring format error #31

Closed BeneficialCode closed 1 year ago

BeneficialCode commented 1 year ago

We should use %*.*ws or %.*ws to printf unicode string. If we use %*ws, the format will cause error string on the command. image

CodeMaxx commented 1 year ago

Can you paste the contents of your ktrace.d file?

BeneficialCode commented 1 year ago
#pragma D option quiet
#pragma D option destructive

struct ustr{uint16_t buffer[256];};

inline uintptr_t MmHighestUserAddress = 0x7FFFFFFEFFFF;

int found;
PETHREAD ethread_ptr;

BEGIN
{
    found = 0;
    ethread_ptr=0;
}

syscall::Nt*:entry
{
    if (probefunc == "NtQueryValueKey")
    {
        temp = ((PUNICODE_STRING)arg1)->Buffer;
        len = ((PUNICODE_STRING)arg1)->Length / 2;
        printf("%Y: 0x%p value name: %*ws\n", walltimestamp, curthread, len,
            ((struct ustr*)temp)->buffer);
    }

}
CodeMaxx commented 1 year ago

What do you mean by "error string on the command"? I see the same output with both %*ws and %.*ws

BeneficialCode commented 1 year ago
std::wstring a(L"\\Device\\HarddiskVolume3\\Windows\\System32\\notepad.exe1111111");
std::cout << a.length() << std::endl;
printf("%*ws\n",52, a.c_str());
printf("%.*ws\n", 52, a.c_str());

You can test the C code. Then you will know the bug. You know the unicode_string might not be null terminated.

mhndr commented 1 year ago

@BeneficialCode , perhaps using wstr2str could be an option you can consider

BeneficialCode commented 1 year ago

The C code will show the difference between the %ws and %.ws. What do you mean by "using wstr2str"?

CodeMaxx commented 1 year ago

@BeneficialCode You are right, that needs to be fixed as the unicode string might not be null terminated. I will fix that in the examples that we provide.

The other option is to use wstr2str. Here is a D-script corresponding to the one you provided which using wstr2str() and has other improvements as well:

#pragma D option quiet

syscall::NtQueryValueKey:entry
{
    this->us = (userland PUNICODE_STRING)args[1];
    this->val = wstr2str((wchar_t*)copyin((uintptr_t)this->us->Buffer, this->us->Length), this->us->Length/2);
    printf("%Y: 0x%p value name: %s\n", walltimestamp, curthread, this->val);
}