diff --git a/tools/debugger/kdd/kdd.c b/tools/debugger/kdd/kdd.c
index fb8c645355..407b70a21c 100644
--- a/tools/debugger/kdd/kdd.c
+++ b/tools/debugger/kdd/kdd.c
@@ -51,6 +51,8 @@
 
 #include "kdd.h"
 
+// TODO: make fix this to actually use address instead of offset?
+// TODO: Maybe clean something as well?
 /* Windows version details */
 typedef struct {
     uint32_t build;             
@@ -62,6 +64,7 @@ typedef struct {
     uint32_t version;           /* +-> NtBuildNumber */
     uint32_t modules;           /* +-> PsLoadedModuleList */
     uint32_t prcbs;             /* +-> KiProcessorBlock */
+    uint32_t kddl;
 } kdd_os;
 
 /* State of the debugger stub */
@@ -85,6 +88,106 @@ typedef struct {
     kdd_os os;                                 /* OS-specific magic numbers */
 } kdd_state;
 
+/**
+ * @brief Size of pointer on 64 machine
+ */
+#define SIZE_PTR64 8
+
+/**
+ * @brief Size of pointer on 32 machine
+ */
+#define SIZE_PTR32 4
+
+
+/*****************************************************************************
+ * PE and DOS Header related offsets
+ */
+
+/**
+ * @brief Offset in DOS header to look for PE header
+ */
+#define DOS_HDR_PE_OFF 0x3c
+
+/**
+ * @brief Size of PE header offset field in DOS header
+ */
+#define DOS_HDR_PE_SZ 4
+
+/**
+ * @brief Offset of number of sections field in PE header
+ */
+#define PE_NUM_SECTION_OFF 0x6
+
+/**
+ * @brief Size of number of sections field in PE header
+ */
+#define PE_NUM_SECTION_SZ 2
+
+/**
+ * @brief Offset of optional header size field in PE header
+ */
+#define PE_OPT_HDR_SZ_OFF 0x14
+
+/**
+ * @brief Size of optional header size field in PE header
+ */
+#define PE_OPT_HDR_SZ_SZ 2
+
+/**
+ * @brief Size of PE header
+ */
+#define PE_HDR_SZ 0x18
+
+/**
+ * @brief Size of section header entries in PE
+ */
+#define PE_SECT_ENT_SZ 0x28
+
+/**
+ * @brief Offset of name field in section header entry
+ */
+#define PE_SECT_NAME_OFF 0
+
+/**
+ * @brief Size of name field in section header entry
+ */
+#define PE_SECT_NAME_SZ 0x8
+
+/**
+ * @brief Offset of virtual address (RVA) field in section header entry
+ */
+#define PE_SECT_RVA_OFF 0xc
+
+/**
+ * @brief Offset of virtual size field in section header entry
+ */
+#define PE_SECT_VSIZE_OFF 0x8
+
+/**
+ * @brief Size of DBGKD_GET_VERSION64 struct
+ */
+#define DBGKD_GET_VERSION64_SZ 0x28
+
+/**
+ * @brief Offset of KERN_BASE in DBGKD_GET_VERSION64 struct
+ */
+#define DBGKD_KERN_BASE_OFF 0x10
+
+/**
+ * @brief Offset of PsLoadedModulesList in DBGKD_GET_VERSION64 struct
+ */
+#define DBGKD_MOD_LIST_OFF 0x18
+
+/**
+ * @brief Offset of DebuggerDataList in DBGKD_GET_VERSION64 struct
+ */
+#define DBGKD_KDDL_OFF 0x20
+
+/**
+ * @brief Offset of DebuggerDataList in DBGKD_GET_VERSION64 struct
+ */
+#define DBGKD_MINOR_OFF 0x2
+
 /*****************************************************************************
  *  Utility functions
  */
@@ -390,6 +493,284 @@ static void find_os(kdd_state *s)
     s->os = unknown_os;
 }
 
+#if 0
+/**
+ * @brief Temporary function for printing memory dump while debugging
+ * Dumps in the format of QWORD type
+ *
+ * @param s Pointer to the kdd_state structure
+ * @param addr Address to start dumping memory from
+ * @param size Number of bytes to print (automatically aligned to higher
+ * multiple of 8 bytes
+ *
+ * @note TODO: Remove this before pushing to master
+ * @note TODO: Maybe add level of logging to kdd (using -v option) - The
+ * idea of using printf instead of KDD_LOG was to not print all other unwanted
+ * logging output
+ */
+static void my_memdump(kdd_state *s, uint64_t addr, int size)
+{
+    int ret;
+    uint64_t buf;
+
+    // we don't handle mis-aligned addresses
+    if (addr & 7) {
+        // XXX: TODO: don't do this
+        return;
+    }
+
+    // dump memory 1 QWORD at a time
+    // format: <address> [offset from start]: dump1 dump2
+    for (int i = 0; i < size; i += 16) {
+
+        // read 8 bytes - on failure, break
+        ret = kdd_read_virtual(s, s->cpuid, addr + i, 8, &buf);
+        if (ret != 8) {
+            break;
+        }
+
+        // print first part
+        printf("0x%p [+0x%03x]: %p ", (void *)(addr + i), i, (void *)buf);
+
+        // read next 8 bytes and print it
+        ret = kdd_read_virtual(s, s->cpuid, addr + i + 8, 8, &buf);
+        if (ret != 8) {
+            break;
+        }
+        printf("%p\n", (void *)buf);
+    }
+    printf("\n");
+}
+#endif
+
+/**
+ * @brief Parse the memory at \a filebase as a valid DOS header and get virtual
+ * address offset and size for any given section name (if it exists)
+ *
+ * @param s Pointer to the kdd_state structure
+ * @param filebase Base address of the file structure
+ * @param sectname Pointer to the section name c-string to look for
+ * @param vaddr Pointer to write the virtual address of section start to
+ * (if found)
+ * @param visze Pointer to write the section size to (if found)
+ *
+ * @return -1 on failure to find the section name
+ * @return 0 on success
+ */
+static int get_pe64_sections(kdd_state *s, uint64_t filebase, char *sectname,
+        uint64_t *vaddr, uint32_t *vsize)
+{
+    uint8_t buf[0x30];
+    uint64_t pe_hdr;
+    uint64_t sect_start;
+    uint16_t num_sections;
+    int ret;
+
+    ret = -1;
+
+    if (!s->os.w64) {
+        return ret;
+    }
+
+    // read PE header offset
+    if (kdd_read_virtual(s, s->cpuid, filebase + DOS_HDR_PE_OFF, DOS_HDR_PE_SZ,
+                buf) != DOS_HDR_PE_SZ) {
+        return -1;
+    }
+
+    pe_hdr = filebase + *(uint32_t *)buf;
+
+    // read number of sections
+    if (kdd_read_virtual(s, s->cpuid, pe_hdr + PE_NUM_SECTION_OFF,
+                PE_NUM_SECTION_SZ, &buf) != PE_NUM_SECTION_SZ) {
+        return -1;
+    }
+    num_sections = *(uint16_t *)buf;
+
+    // read size of optional header
+    if (kdd_read_virtual(s, s->cpuid, pe_hdr + PE_OPT_HDR_SZ_OFF,
+                PE_OPT_HDR_SZ_SZ, &buf) != PE_OPT_HDR_SZ_SZ) {
+        return -1;
+    }
+
+    // 0x18 is the size of PE header
+    sect_start = pe_hdr + PE_HDR_SZ + *(uint16_t *)buf;
+
+    for (int i = 0; i < num_sections; i++) {
+        if (kdd_read_virtual(s, s->cpuid, sect_start + (i * PE_SECT_ENT_SZ),
+                    PE_SECT_ENT_SZ, &buf) != PE_SECT_ENT_SZ) {
+            return -1;
+        }
+
+        if (!strncmp(sectname, (char *)(buf + PE_SECT_NAME_OFF),
+                    PE_SECT_NAME_SZ)) {
+            *vaddr = filebase + *(uint32_t *)(buf + PE_SECT_RVA_OFF);
+            *vsize = *(uint32_t *)(buf + PE_SECT_VSIZE_OFF);
+            ret = 0;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Get the OS information like base address, minor version,
+ * PsLoadedModuleList and DebuggerDataList (basically the fields of
+ * DBGKD_GET_VERSION64 struture required to do handshake?).
+ *
+ * This is done by reading the IDT entry for divide-by-zero exception and
+ * searching back into the memory for DOS header (which is our kernel base).
+ * Once we have the kernel base, we parse the PE header and look for kernel
+ * base address in the .data section. Once we have possible values, we look for
+ * DBGKD_GET_VERSION64 block by using following heuristics on the address which
+ * has the kernel base:
+ *
+ *  - at address [-0x10], it should have 0xf as the MajorVersion
+ *  - at address [+0x8], it should have a valid kernel memory address pointing
+ *  in .data
+ *  - at address [+0x10], it should have a valid kernel memory address pointing
+ *  in .data
+ *
+ * @param s Pointer to the kdd state
+ */
+static void get_os_info_64(kdd_state *s)
+{
+    kdd_ctrl ctrl;
+    int ret;
+    uint64_t buf;
+    uint64_t idt0_addr;
+    uint64_t base;
+    uint64_t caddr;
+    uint64_t data_base;
+    uint32_t data_size;
+    uint64_t modptr;
+    uint64_t kddl;
+    uint16_t minor;
+    uint8_t dbgkd_get_version64[0x28];
+
+    /* TODO: right now, we are forcing this to 1 (as we only support 64 bit
+     * system, however, we should use kdd_state or hvm calls to check if we are
+     * in 64-bit
+     */
+    s->os.w64 = 1;
+
+    // if we are no in 64-bit mode, fail
+    if (!s->os.w64) {
+        goto fail;
+    }
+
+    // get control registers for our os
+    ret = kdd_get_ctrl(s->guest, s->cpuid, &ctrl, s->os.w64);
+    if (ret) {
+        goto fail;
+    }
+
+    // read the div-by-zero handler function address
+    kdd_read_virtual(s, s->cpuid, ctrl.c64.idt_base + 8, 8, &buf);
+    idt0_addr = ((uint64_t)buf << 32) & 0xffffffff00000000;
+
+    kdd_read_virtual(s, s->cpuid, ctrl.c64.idt_base, 8, &buf);
+    idt0_addr |= ((buf >> 32) & 0xffff0000);
+    idt0_addr |= (buf & 0xffff);
+
+    KDD_LOG(s, "idt0 addr: %p\n", (void *)idt0_addr);
+    printf("idt0 addr: %p\n", (void *)idt0_addr);
+
+    // get the page start and look for "MZ" file header
+
+    base = idt0_addr & ~(PAGE_SIZE - 1);
+    // printf("%p\n", (void *)base);
+
+    while (1) {
+        uint16_t val;
+        if (kdd_read_virtual(s, s->cpuid, base, 2, &val) != 2) {
+            // just move going back?? this is bad though
+            printf("ran into unmapped region without finding PE header\n");
+        }
+
+        if (val == 0x5a4d) { // MZ
+            // printf("maybe success\n");
+            break;
+        }
+
+        base -= PAGE_SIZE;
+    }
+
+    KDD_LOG(s, "base: %p\n", (void *)base);
+
+    // found the data section start
+    if (get_pe64_sections(s, base, ".data", &data_base, &data_size)) {
+        goto fail;
+    }
+
+    // look for addresses which has kernel base written into it
+    caddr = data_base;
+
+    modptr = 0;
+    kddl = 0;
+    minor = 0;
+
+    while (caddr < data_base + data_size) {
+        if (kdd_read_virtual(s, s->cpuid, caddr, SIZE_PTR64, &buf) !=
+                SIZE_PTR64) {
+            // reached end and found nothing
+            goto fail;
+        }
+
+        // if we found base in the memory addresses
+        if (buf == base) {
+            // read the DBGKD_GET_VERSION64 struct
+            if (kdd_read_virtual(s, s->cpuid, caddr - DBGKD_KERN_BASE_OFF,
+                        DBGKD_GET_VERSION64_SZ, dbgkd_get_version64) ==
+                    DBGKD_GET_VERSION64_SZ) {
+                // check if major version is 0xf
+                if (dbgkd_get_version64[0] == '\x0f') {
+
+                    // read minor version, PsLoadedModuleList pointer and
+                    // DebuggerDataList
+                    modptr =
+                        *(uint64_t *)(dbgkd_get_version64 + DBGKD_MOD_LIST_OFF);
+                    kddl = *(uint64_t *)(dbgkd_get_version64 + DBGKD_KDDL_OFF);
+                    minor =
+                        *(uint16_t *)(dbgkd_get_version64 + DBGKD_MINOR_OFF);
+
+                    // do heuristic check
+                    if (modptr && kddl && modptr != kddl && kddl != base &&
+                            base != modptr && modptr >= data_base &&
+                            modptr < (data_base + data_size) &&
+                            kddl >= data_base &&
+                            kddl < (data_base + data_size)) {
+                        // my_memdump(s, caddr - 0x10, 0x30);
+                        break;
+                    }
+
+                }
+            }
+
+        }
+
+        caddr += sizeof(void *);
+    }
+
+    // TODO: use KDD_LOG?
+    printf("base: %p\n", (void *)base);
+    printf("modules list: %p\n", (void *)modptr);
+    printf("kddl: %p\n", (void *)kddl);
+    printf("minor version: 0x%hx\n", minor);
+
+    s->os.base = base;
+    s->os.modules = modptr - base;
+    s->os.kddl = kddl - base;
+    s->os.build = (uint32_t) minor;
+    return;
+
+fail:
+    // XXX: TODO: handle failure case
+    s->os = unknown_os;
+    return;
+}
+
 
 /*****************************************************************************
  *  How to send packets and acks.
@@ -534,6 +915,12 @@ static void kdd_handle_handshake(kdd_state *s)
 {
     /* Figure out what we're looking at */
     find_os(s);
+
+    /* if unknown os, use the idt method */
+    if (!s->os.base) {
+        get_os_info_64(s);
+    }
+
     kdd_send_string(s, "[kdd: %s @0x%"PRIx64"]\r\n", s->os.name, s->os.base);
 
     /* Respond with some details about the debugger stub we simulate */
@@ -555,7 +942,7 @@ static void kdd_handle_handshake(kdd_state *s)
     s->txp.cmd.shake.u3[2]     = 0x55;
     s->txp.cmd.shake.kern_addr = s->os.base;
     s->txp.cmd.shake.mods_addr = s->os.base + s->os.modules;
-    s->txp.cmd.shake.data_addr = 0; /* Debugger data probably doesn't exist */
+    s->txp.cmd.shake.data_addr = s->os.base + s->os.kddl; // 0; /* Debugger data probably doesn't exist */
 
     KDD_LOG(s, "Client initial handshake: %s\n", s->os.name);
     kdd_send_cmd(s, KDD_CMD_SHAKE, 0);
