April 20, 2024, 12:49:56 AM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Wstrings and STATUS_DATATYPE_MISALIGNMENT

Started by Andy, October 05, 2017, 04:01:23 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andy

October 05, 2017, 04:01:23 AM Last Edit: October 05, 2017, 04:14:24 AM by Andy
Not one to give up, I thought I'd have a look at the NtRenameKey function again.

And I declare it as:
declare extern NtRenameKey(hKey as uint,Name as wstring),Uint

Now I haven't really used Wstrings very much but when I pass hKey (a handle) and Name (a Wstring) to the NtRenameKey function it returns with the error STATUS_DATATYPE_MISALIGNMENT.

Sapero posted something about this here:

http://www.ionicwind.com/forums/index.php?topic=1693.msg15605#msg15605 and

http://www.ionicwind.com/forums/index.php?topic=1060.msg9818#msg9818

- but as most things with Sapero it just has me confused.

This what I'm trying (but you won't be able to compile it):


$include "registrylib.inc"

declare extern NtRenameKey(hKey as uint,Name as wstring),Uint

UINT hInst=LoadLibrary("ntdll.dll")
UINT proc = GetProcAddress(hInst,"NtRenameKey")

uint rHandle = 0
string dummy = ""
wstring w = s2w("ATEST\x00")

openconsole
print
print
print "  Library ntdll.dll handle ",hInst," is ok"
print "  NtRenameKey Proc handle ",proc," is ok"

rHandle = RegCreateKeyHandle("HKEY_CURRENT_USER\\Software\\Test")

print
print "  Handle to key I want to rename ",rHandle," is ok"
print
print "  Result ",!<NtRenameKey>proc(rHandle,w)," error! (STATUS_DATATYPE_MISALIGNMENT)"
print
print

'RegCloseKey(rHandle)
FreeLibrary(hInst)

do:until inkey$ <> ""
closeconsole
end


I'm trying to rename the key from "Test" to "ATEST".

Any ideas anyone?

Thanks.

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Brian

Andy,

Doesn't S2W convert an ANSI string to wide string? You are already putting a
WSTRING in and asking to convert it to a WSTRING, as well. Maybe it should
just be STRING w=S2W

Brian

Andy

Brian,

Making "w" a string gives a compiler error.

The other thing that confuses me is that the help file says a wstring is 512 in length, but when I use the sizeof(w) command it returns 510?

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Brian

Andy,

Have you looked at the UNICODE command in the Help File? It may do what you want

Brian

Andy

The unicode section of the help file tells me wstrings are automatically set to 255 characters so why it should double using sizeof(x) to 510 is a mystery.

I'm wondering if the declare line is correct?

declare extern NtRenameKey(hKey as uint,Name as Wstring),Uint

This is a link from ms showing the parameters of NtRenameKey function:

https://msdn.microsoft.com/en-us/library/cc512138(v=vs.85).aspx

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

Quote from: Andy on October 06, 2017, 03:29:18 AM
The unicode section of the help file tells me wstrings are automatically set to 255 characters so why it should double using sizeof(x) to 510 is a mystery
255 characters, 2 bytes per character.

Andy

Thanks Jalih,

That answers that question, so the next question is:

Do we have to pad every normal string character to 2 bytes so that the string and wstring are aligned?

And isn't that what the S2W command is doing?

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

fasecero

Hi Andy, I don't have much time to look at this right now but I think this will not be an easy task. Some hints:

NTSTATUS NtRenameKey(uint KeyHandle, POINTER NewName);

- Not sure if you can use a key from RegOpenKeyEx as KeyHandle in NtRenameKey. Maybe NtRenameKey param needs to be adquired by using NtOpenKey or NtOpenKeyEx, I have never use these. But I repeat, I am not sure about this.

- NewName is not a pointer to wstring, it's a pointer to UNICODE_STRING structure
https://msdn.microsoft.com/en-us/library/windows/hardware/ff564879(v=vs.85).aspx

You need to declare a UNICODE_STRING, use RtlZeroMemory on it and then you can initialize it with RtlUnicodeStringInit  :P

fasecero

Well, I did check these ideas... RegOpenKeyEx works just fine, there's no RtlUnicodeStringInit at Sapero's includes so I just hard code the UNICODE struct. The example rename "HKEY_CURRENT_USER\Software\temp" to "HKEY_CURRENT_USER\Software\TEST_RENAMED"


$INCLUDE "windowssdk.inc"
$INCLUDE "Ntddk.inc"

DECLARE NtRenameKey(UINT hKey, pointer newName), UINT

' -------

UINT hKey = 0
UINT result = 0

IF RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Test", 0, KEY_ALL_ACCESS, hKey) = 0 THEN
result = RenameKey(hKey, L"TEST_RENAMED")
RegCloseKey(hKey)

PRINT GetResultMessage(result)

ENDIF

DO:UNTIL INKEY$ <> ""

' -------

SUB RenameKey(UINT hKey, pointer newName), UINT
UINT result = 0

UINT hInst=LoadLibrary("ntdll.dll")

IF hInst THEN
UINT proc = GetProcAddress(hInst,"NtRenameKey")

IF proc THEN
UNICODE_STRING ReplacementName
RtlZeroMemory(&ReplacementName, LEN(ReplacementName))

WCHAR temp = 0
ReplacementName.Buffer = newName
ReplacementName.Length = wcslen(newName) * LEN(temp)
ReplacementName.MaximumLength = LEN(newName)

result = !<NtRenameKey>proc(hKey, &ReplacementName)
ENDIF

FreeLibrary(hInst)
ENDIF

RETURN result
ENDSUB

SUB GetResultMessage(uint _Erro), STRING
STRING message = ""

uint nSize = 0
uint Arguments = 0
POINTER ErMes = 0

FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,0,_Erro,0, &ErMes,nSize,Arguments)
message = *<string>ErMes
LocalFree(ErMes)

RETURN message
ENDSUB


Andy

Fasecero,

Yes that really works, and it's fast, just one little thing, I had to amend the ntdef.inc file from:

$ifndef __IWBIDE__
typedef BYTE Schar


To:

$ifndef __IWBIDE__
'typedef BYTE Schar


So I've made a copy with the amendment and I'm using that include file instead.

But thanks again for solving this one!
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

fasecero

Aw, just remove temp variable completely and replace the code below so there's no need to modify that file

ReplacementName.Buffer = newName
ReplacementName.Length =  2 * wcslen(newName)
ReplacementName.MaximumLength = LEN(newName)

Andy

October 11, 2017, 04:55:34 AM #11 Last Edit: October 11, 2017, 05:00:21 AM by Andy
Been delayed a couple of days so I've only just got back to this.

I tried that, it didn't work then it dawned on me it won't because it's actually a definition in ntdef.inc which is included at compile time.

So the only way around it is to comment out the line in ntdef.inc:

'typedef BYTE schar

and save it as something like ntdef2.inc - and include this in any code.

$INCLUDE "windowssdk.inc"
$INCLUDE "Ntdef2.inc"



Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

October 12, 2017, 12:10:09 AM #12 Last Edit: October 12, 2017, 12:14:05 AM by Andy
Thanks everybody for helping with this topic.

For me it was about two things:

1. How to overcome / use unicode strings, that is how to pass a normal string to a unicode string and avoid "data misalignment" (something I'd never heard of before) at compile time.

2. Using a native Ntdll function to see if it any quicker than an api call - which it is.  After testing both NtRenameKey (ntdll) and RegCopyTree plus RegDeleteKey (Advapi32) I found that NtRenameKey was twice as fast.

NtRenameKey returns after around 15 milliseconds, where the Advapi32 functions return after around 31 milliseconds.

Although as a human, the difference of around 15 / 16 milliseconds makes no noticeable difference in performance / response to me (although it might on a very large registry key).

Should I replace RegCopyTree plus RegDeleteKey (Advapi32) with NtRenameKey (ntdll)? I will think on that one.....

Once again guys, Thanks!!!
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.