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.
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
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?
Andy,
Have you looked at the UNICODE command in the Help File? It may do what you want
Brian
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
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.
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?
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
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
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!
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)
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"
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!!!