Пример #1
0
static PyObject *
py_hivex_node_get_child (PyObject *self, PyObject *args)
{
  PyObject *py_r;
  errno = 0;
  hive_node_h r;
  hive_h *h;
  PyObject *py_h;
  long node;
  char *name;

  if (!PyArg_ParseTuple (args, (char *) "Ols:hivex_node_get_child", &py_h, &node, &name))
    return NULL;
  h = get_handle (py_h);
  r = hivex_node_get_child (h, node, name);
  if (r == 0 && errno != 0) {
    PyErr_SetString (PyExc_RuntimeError,
                     strerror (errno));
    return NULL;
  }

  if (r)
    py_r = PyLong_FromLongLong (r);
  else {
    Py_INCREF (Py_None);
    py_r = Py_None;
  }
  return py_r;
}
Пример #2
0
int64_t
do_hivex_node_get_child (int64_t nodeh, const char *name)
{
  int64_t r;

  NEED_HANDLE (-1);

  errno = 0;
  r = hivex_node_get_child (h, nodeh, name);
  if (r == 0 && errno != 0) {
    reply_with_perror ("failed");
    return -1;
  }

  return r;
}
Пример #3
0
hive_node_h
hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name)
{
  CHECK_WRITABLE (0);

  if (!IS_VALID_BLOCK (h, parent) || !block_id_eq (h, parent, "nk")) {
    SET_ERRNO (EINVAL, "invalid block or not an 'nk' block");
    return 0;
  }

  if (name == NULL || strlen (name) == 0) {
    SET_ERRNO (EINVAL, "name is NULL or zero length");
    return 0;
  }

  if (hivex_node_get_child (h, parent, name) != 0) {
    SET_ERRNO (EEXIST, "a child with that name exists already");
    return 0;
  }

  size_t recoded_name_len;
  int use_utf16 = 0;
  char *recoded_name =
    _hivex_encode_string (h, name, &recoded_name_len, &use_utf16);
  if (recoded_name == NULL) {
    SET_ERRNO (EINVAL, "malformed name");
    return 0;
  }

  /* Create the new nk-record. */
  static const char nk_id[2] = { 'n', 'k' };
  size_t seg_len = sizeof (struct ntreg_nk_record) + recoded_name_len;
  hive_node_h nkoffset = allocate_block (h, seg_len, nk_id);
  if (nkoffset == 0) {
    free (recoded_name);
    return 0;
  }

  DEBUG (2, "allocated new nk-record for child at 0x%zx", nkoffset);

  struct ntreg_nk_record *nk =
    (struct ntreg_nk_record *) ((char *) h->addr + nkoffset);
  if (use_utf16)
    nk->flags = htole16 (0x0000);
  else
    nk->flags = htole16 (0x0020);
  nk->parent = htole32 (parent - 0x1000);
  nk->subkey_lf = htole32 (0xffffffff);
  nk->subkey_lf_volatile = htole32 (0xffffffff);
  nk->vallist = htole32 (0xffffffff);
  nk->classname = htole32 (0xffffffff);
  nk->name_len = htole16 (recoded_name_len);
  memcpy (nk->name, recoded_name, recoded_name_len);
  free (recoded_name);

  /* Inherit parent sk. */
  struct ntreg_nk_record *parent_nk =
    (struct ntreg_nk_record *) ((char *) h->addr + parent);
  size_t parent_sk_offset = le32toh (parent_nk->sk);
  parent_sk_offset += 0x1000;
  if (!IS_VALID_BLOCK (h, parent_sk_offset) ||
      !block_id_eq (h, parent_sk_offset, "sk")) {
    SET_ERRNO (EFAULT,
               "parent sk is not a valid block (%zu)", parent_sk_offset);
    return 0;
  }
  struct ntreg_sk_record *sk =
    (struct ntreg_sk_record *) ((char *) h->addr + parent_sk_offset);
  sk->refcount = htole32 (le32toh (sk->refcount) + 1);
  nk->sk = htole32 (parent_sk_offset - 0x1000);

  /* Inherit parent timestamp. */
  nk->timestamp = parent_nk->timestamp;

  /* What I found out the hard way (not documented anywhere): the
   * subkeys in lh-records must be kept sorted.  If you just add a
   * subkey in a non-sorted position (eg. just add it at the end) then
   * Windows won't see the subkey _and_ Windows will corrupt the hive
   * itself when it modifies or saves it.
   *
   * So use get_children() to get a list of intermediate records.
   * get_children() returns these in reading order (which is sorted),
   * so we look for the lf/lh/li-records in sequence until we find the
   * key name just after the one we are inserting, and we insert the
   * subkey just before it.
   *
   * The only other case is the no-subkeys case, where we have to
   * create a brand new lh-record.
   */
  hive_node_h *unused;
  size_t *blocks;

  if (_hivex_get_children (h, parent, &unused, &blocks, 0) == -1)
    return 0;
  free (unused);

  size_t i;
  size_t nr_subkeys_in_parent_nk = le32toh (parent_nk->nr_subkeys);

  if (nr_subkeys_in_parent_nk == UINT32_MAX) {
    free (blocks);
    SET_ERRNO (EOVERFLOW,
               "too many subkeys (%zu)", nr_subkeys_in_parent_nk);
    return 0;
  }

  if (nr_subkeys_in_parent_nk == 0) { /* No subkeys case. */
    /* Free up any existing intermediate blocks. */
    for (i = 0; blocks[i] != 0; ++i)
      mark_block_unused (h, blocks[i]);
    size_t lh_offs = new_lh_record (h, name, nkoffset);
    if (lh_offs == 0) {
      free (blocks);
      return 0;
    }

    /* Recalculate pointers that could have been invalidated by
     * previous call to allocate_block (via new_lh_record).
     */
    /* nk could be invalid here */
    parent_nk = (struct ntreg_nk_record *) ((char *) h->addr + parent);

    DEBUG (2, "no keys, allocated new lh-record at 0x%zx", lh_offs);

    parent_nk->subkey_lf = htole32 (lh_offs - 0x1000);
  }
  else {                        /* Insert subkeys case. */
    if (insert_subkey (h, name, parent, nkoffset, blocks) == -1) {
      free (blocks);
      return 0;
    }

    /* Recalculate pointers that could have been invalidated by
     * previous call to allocate_block (via new_lh_record).
     */
    /* nk could be invalid here */
    parent_nk = (struct ntreg_nk_record *) ((char *) h->addr + parent);
  }

  free (blocks);

  /* Update nr_subkeys in parent nk. */
  nr_subkeys_in_parent_nk++;
  parent_nk->nr_subkeys = htole32 (nr_subkeys_in_parent_nk);

  /* Update max_subkey_name_len in parent nk. */
  size_t utf16_len = use_utf16 ? recoded_name_len : recoded_name_len * 2;
  if (le16toh (parent_nk->max_subkey_name_len) < utf16_len)
    parent_nk->max_subkey_name_len = htole16 (utf16_len);

  return nkoffset;
}