RegRenameKey – Hidden registry API

September 29, 2015

2 comments

While working on a pet project called Registry Explorer (yes, I know there are a bunch of those floating around, most of them pretty old) to be yet another RegEdit.exe replacement, I wanted to add the option to rename a registry key (which RegEdit.exe allows as well). However, looking at the registry APIs (both managed and native) there seems to be no function to rename a key. The closest is the ability to copy a key (with its subkeys and values) via RegCopyTree, so that I can copy the original key with the new name and delete the original one. Although this could work, it seems wasteful; after all – the subkey tree could be very deep with multitude of keys and values, making copy a slow operation and possibly a memory hungry one.

Since regedit allows renaming of a key I wandered whether it has some trick up its sleeve. I’ve opened DependencyWalker and looked at the imported function from AdvApi32.dll (where the Registry APIs reside). And sure enough – there seems to be a renaming key function:

image

Alas, the function is clearly undocumented in the MSDN docs. I suspect it’s just an oversight, wouldn’t you?

The function is clearly exported, so all I need to do is add the correct prototype. So I guessed the function could have at least two arguments: the handle to the registry key to rename and the new name itself. Let’s see if we can use tools to help get to the correct prototype.

First, it would be nice to know the number of arguments to the function. It may be two (as per my guess) but it may be more – perhaps some flags, or something else. We can use the link.exe tool with the /dump and /export switches to list the mangled function names in the import library advapi32.lib.

If you want to try this, open the Visual Studio command prompt (any version will do) so that the environment variables are set correctly to find the link.exe tool. (alternatively, just go and find that tool somewhere in the VS directory hierarchy) and pass the full path of AdvApi32.lib (typically at c:\Program Files (x86)\Windows kits\10\Lib\10.0.10240.0\um\x86 if using the Windows 10 SDK installation).

C:\Program Files (x86)\Microsoft Visual Studio 12.0>link /dump /exports "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\um\x86\AdvAPI32.Lib"

The result is a long list of functions, but RegRenameKey is there:

_RegRenameKey@12

Since I’ve used the 32 bit import library this tells us that the arguments take up 12 bytes, which we can guess as being three arguments.

Next, we’ll fire up WinDbg (with admin elevation because RegEdit runs as admin as well) and attach to a RegEdit.Exe instance. Now we can set up a breakpoint at RegRenameKey:

0:000> bp advapi32!regrenamekey

Now we let regedit continue running and when adding a new key or renaming an existing key, we hit the breakpoint:

Breakpoint 0 hit
ADVAPI32!RegRenameKey:
00007ffd`678c0960 4c8bdc          mov     r11,rsp

I’ve attached to the 64 bit version of RegEdit. In x64 there is just one calling convention. The first 4 integer/pointer arguments are passed in the RCX, RDX, R8, R9 registers, respectively. Since we suspect the first argument is a handle to a registry key – let’s check our hypothesis:

0:000> !handle @rcx 7
Handle 1c4
  Type             Key
  Attributes       0
  GrantedAccess    0xf003f:
         Delete,ReadControl,WriteDac,WriteOwner
         QueryValue,SetValue,CreateSubKey,EnumSubKey,Notify,CreateLink
  HandleCount      2
  PointerCount     32769
  Name             \REGISTRY\USER\S-1-5-21-3251691949-2960433927-2607893006-1001\Environment\New Key #1

Indeed, the first argument is a handle to the key with the old name (“New Key 1”). How about the second argument?

0:000> r rdx
rdx=0000000000000000

It seems RDX is zero which may be some zero flags or a null pointer or a null handle. Let’s try the third argument in R8:

0:000> r r8
r8=000000060f3bf720

There’s definitely something there. Since the new name must be somewhere, let’s see if this is a string:

0:000> du @r8
00000006`0f3bf720  "zzz"

And it is the new name I’ve set for the key. So these are the 3 arguments.

After some code testing, I’ve determined that the second argument can be the old key name if the handle is to the parent key. It can be null if the key handle points directly to the old key (and not to the parent).

This is the final prototype for the Win32 API:

int RegRenameKey(HANDLE hKey, LPCWSTR oldName, LPCWSTR newName);

The returned value is the error code which is the way all registry API calls work. They don’t return the typical Win32 BOOL; rather, they return the error code directly (zero being ERROR_SUCCESS).

Since my Registry Explorer is a WPF app, I’m using P/Invoke, so the call looks like so:

[DllImport("advapi32")]
public static extern int RegRenameKey(SafeRegistryHandle hKey, [MarshalAs(UnmanagedType.LPWStr)] string oldname,
[MarshalAs(UnmanagedType.LPWStr)] string newname);

There you have it – renaming a registry key with a hidden API.

Add comment
facebook linkedin twitter email

Leave a Reply to Gentil Kiwi Cancel Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

2 comments

  1. Gentil KiwiOctober 4, 2015 ב 00:52

    there seems to be no function to rename a key
    There is a native function to rename key: NtRenameKey, and it’s documented.

    This function is used in RegRenameKey:

    LONG __stdcall RegRenameKey(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpNewKeyName)
    {
    LONG result; // eax@2
    NTSTATUS status; // edi@3
    UNICODE_STRING NewName; // [sp+4h] [bp-Ch]@3
    HKEY phkResult; // [sp+Ch] [bp-4h]@1

    phkResult = hKey;
    if ( !lpSubKey || (result = RegOpenKeyExW(hKey, lpSubKey, 0, 0x20006u, &phkResult)) == 0 )// KEY_WRITE
    {
    RtlInitUnicodeStringEx(&NewName, lpNewKeyName);
    status = NtRenameKey(phkResult, &NewName);
    if ( phkResult != hKey )
    RegCloseKey(phkResult);
    result = RtlNtStatusToDosError(status);
    }
    return result;
    }

    Reply
  2. omarMarch 26, 2017 ב 13:58

    Dont work..:
    using Microsoft.Win32;
    using Microsoft.Win32.SafeHandles;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading.Tasks;

    namespace ConsoleApplication7
    {
    class Program
    {
    private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(-2147483646);
    [DllImport(“advapi32”)]
    public static extern int RegRenameKey(SafeRegistryHandle hKey, [MarshalAs(UnmanagedType.LPWStr)] string oldname,
    [MarshalAs(UnmanagedType.LPWStr)] string newname);
    [DllImport(“Advapi32.dll”, EntryPoint = “RegOpenKeyExW”, CharSet = CharSet.Unicode)]
    public static extern int RegOpenKeyEx(IntPtr hKey, [In] string lpSubKey, int ulOptions, int samDesired, out IntPtr phkResult);

    static void Main(string[] args)
    { //mhmmm si, todo esta bien , bueno ire a ver lo que iba oka ver
    ///Estas intentando renombrar una clave de registro una la crpeta que la contiene…
    IntPtr result;

    SafeRegistryHandle hKey = null;//no es necesario, esta funcuonando, si no, no me hubiere retorando un int
    hKey = new SafeRegistryHandle(HKEY_LOCAL_MACHINE,true);
    int resul = RegOpenKeyEx(HKEY_LOCAL_MACHINE, “\\SOFTWARE\\Company”, 0,0,out result);
    Console.WriteLine(resul);
    int rosul = RegRenameKey(hKey, “SOFTWARE\\Company\\”, “SOFTWARE\\Editado\\”);
    Console.WriteLine(rosul);
    Console.ReadLine(); //Ok a ver dejamever unos ejemplos de advapi, los tienes ahi? mierdaaa no tiees ideas de los peos que se acaba de tirar mi perro

    }
    }
    }

    Reply