Nmap Development mailing list archives

Re: New hexdump() function for nbase/nmap


From: "Luis M." <luis.mgarc () gmail com>
Date: Tue, 25 Aug 2009 17:50:17 +0100

Hi David,

David Fifield wrote:
On Tue, Aug 25, 2009 at 11:41:20AM +0100, Luis M. wrote:
  
Nmap currently uses two functions to dump hex bytes to stdout. One of
them, hdump(), just prints raw hex bytes (no ASCII equivalents) and the
other one, lamont_hdump() has a bug when printing buffers where
bufflen%16==3. I've just implemented a new version from scratch,
hopefully bug-free, that basically produces the same output as
Wireshark. Output looks like this:

0000   e8 60 65 86 d7 86 6d 30  35 97 54 87 ff 67 05 9e  .`e...m05.T..g..
0010   07 5a 98 c0 ea ad 50 d2  62 4f 7b ff e1 34 f8 fc  .Z....P.bO{..4..
0020   c4 84 0a 6a 39 ad 3c 10  63 b2 22 c4 24 40 f4 b1  ...j9.<.c.".$@..

I attach two patches. One of them includes the new function into nbase
and the other one replaces calls to the old functions in nmap's code.
Can some of you guys, please have a look at the patches, so I have a
second opinion before applying them. Thanks.
    

Keeping a buffer of a whole line is a good idea. The code looks correct
but to me it's a bit hard to understand. I suggest a loop structure that
mirrors the output: one line at a time, each line of 16 bytes. Like
this:

i = 0;
while (i < length) {
      fill line with spaces
      add line number
      do {
              if (i % 16 == 8)
                      add space
              add hex of cp[i]
              add ascii of cp[i]
              i++
      } while (i < length && i % 16 != 0);
      copy line to output
}

  
Ok, no problem, I rewrote the code. I hope now it's easier to
understand. I attach the new version.

The cp parameter should be const. Why are there 257, not 256, elements
in the asciify array? Nothing is ever stored or read from the final
element.
  
Yes, you are right. I changed it back to 256. Sometimes I just add an
extra element in arrays so if I make a mistake and write one byte past
the end of the desired length it doesn't overwrite the next declared
variable.

Luis.


Index: nbase/nbase_misc.c
===================================================================
--- nbase/nbase_misc.c  (revision 15257)
+++ nbase/nbase_misc.c  (working copy)
@@ -101,6 +101,7 @@
 #include <winsock2.h>
 #endif
 
+#include <stdio.h>
 #include "nbase_ipv6.h"
 #include "nbase_crc32ct.h"
 
@@ -504,3 +505,76 @@
 
 #undef ADLER32_BASE
 
+
+/* This function returns a string containing the hexdump of the supplied
+ * buffer. It uses current locale to determine if a character is printable or
+ * not. It prints 73char+\n wide lines like these:
+
+0000   e8 60 65 86 d7 86 6d 30  35 97 54 87 ff 67 05 9e  .`e...m05.T..g.. 
+0010   07 5a 98 c0 ea ad 50 d2  62 4f 7b ff e1 34 f8 fc  .Z....P.bO{..4.. 
+0020   c4 84 0a 6a 39 ad 3c 10  63 b2 22 c4 24 40 f4 b1  ...j9.<.c.".$@.. 
+
+ * The lines look basically like Wireshark's hex dump.
+ * WARNING: This function returs a pointer to a DINAMICALLY allocated buffer
+ * that the caller is supposed to free().
+ * */
+char *hexdump(const u8 *cp, u32 length){
+  static char asciify[257];          /* Stores cha6acter table           */
+  int asc_init=0;                    /* Flag to generate table only once */
+  u32 i=0, hex=0, asc=0;             /* Array indexes                    */
+  u32 line_count=0;                  /* For byte count at line start     */
+  char *current_line=NULL;           /* Current line to write            */
+  char *buffer=NULL;                 /* Dynamic buffer we return         */
+  #define LINE_LEN 74                /* Lenght of printed line           */
+  char line2print[LINE_LEN];         /* Stores current line              */
+  char printbyte[16];                /* For byte conversion              */
+  memset(line2print, ' ', LINE_LEN); /* We fill the line with spaces     */
+
+  /* On the first run, generate a list of nice printable characters
+   * (according to current locale) */
+  if( asc_init==0){
+      asc_init=1;
+      for(i=0; i<256; i++){
+        if( isalnum(i) || isdigit(i) || ispunct(i) ){ asciify[i]=i; }
+        else{ asciify[i]='.'; }
+      }
+  }
+  /* Allocate enough space to print the hex dump */
+  int bytes2alloc=(length%16==0)? (1 + LINE_LEN * (length/16)) : (1 + LINE_LEN * (1+(length/16))) ;
+  buffer=(char *)safe_zalloc(bytes2alloc);
+  current_line=buffer;
+#define HEX_START 7
+#define ASC_START 57
+/* This is how or line looks like.
+0000   00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f  .`e...m05.T..g..[\n]
+01234567890123456789012345678901234567890123456789012345678901234567890123
+0         1         2         3         4         5         6         7
+       ^                                                 ^               ^
+       |                                                 |               |
+    HEX_START                                        ASC_START        Newline
+*/
+  i=0;
+  while( i < length ){
+    memset(line2print, ' ', LINE_LEN); /* Fill line with spaces */
+    sprintf(line2print, "%04x", (16*line_count++) % 0xFFFF); /* Add line No.*/
+    line2print[4]=' '; /* Replace the '\0' inserted by sprintf() with a space */
+    hex=HEX_START;  asc=ASC_START;
+    do { /* Print 16 bytes in both hex and ascii */
+               if (i%16 == 8) hex++; /* Insert space every 8 bytes */
+        sprintf(printbyte,"%02x", cp[i]);/* First print the hex number */
+        line2print[hex++]=printbyte[0];
+        line2print[hex++]=printbyte[1];
+        line2print[hex++]=' ';
+        line2print[asc++]=asciify[ cp[i] ]; /* Then print its ASCII equivalent */
+               i++;
+       } while (i < length && i%16 != 0);
+    /* Copy line to output buffer */
+    line2print[LINE_LEN-1]='\n';
+    memcpy(current_line, line2print, LINE_LEN);
+    current_line += LINE_LEN;
+  }
+  buffer[bytes2alloc-1]='\0'; 
+  return buffer;
+} /* End of hexdump() */
+
+
Index: nbase/nbase.h
===================================================================
--- nbase/nbase.h       (revision 15257)
+++ nbase/nbase.h       (working copy)
@@ -431,6 +431,8 @@
 
 int fselect(int s, fd_set *rmaster, fd_set *wmaster, fd_set *emaster, struct timeval *tv);
 
+char *hexdump(const u8 *cp, u32 length);
+
 #ifndef STDIN_FILENO
 #define STDIN_FILENO 0
 #endif
Index: utils.h
===================================================================
--- utils.h     (revision 15257)
+++ utils.h     (working copy)
@@ -173,8 +173,7 @@
 
 int wildtest(char *wild, char *test);
 
-void hdump(unsigned char *packet, unsigned int len);
-void lamont_hdump(char *cp, unsigned int length);
+void nmap_hexdump(unsigned char *cp, unsigned int length);
 
 /* Compare a canonical option name (e.g. "max-scan-delay") with a
    user-generated option such as "max_scan_delay" and returns 0 if the
Index: utils.cc
===================================================================
--- utils.cc    (revision 15257)
+++ utils.cc    (working copy)
@@ -137,90 +137,19 @@
 
 }
 
+/* Wrapper for nbase function hexdump() */
+void nmap_hexdump(unsigned char *cp, unsigned int length){
 
-
-/* Hex dump */
-void hdump(unsigned char *packet, unsigned int len) {
-unsigned int i=0, j=0;
-
-log_write(LOG_PLAIN, "Here it is:\n");
-
-for(i=0; i < len; i++){
-  j = (unsigned) (packet[i]);
-  log_write(LOG_PLAIN, "%-2X ", j);
-  if (!((i+1)%16))
-    log_write(LOG_PLAIN, "\n");
-  else if (!((i+1)%4))
-    log_write(LOG_PLAIN, "  ");
+ char *string=NULL;
+ string = hexdump((u8*)cp, length);
+ if(string){
+    log_write(LOG_PLAIN, "%s", string);
+    free(string);
+ }
+ return;
 }
-log_write(LOG_PLAIN, "\n");
-}
 
-/* A better version of hdump, from Lamont Granquist.  Modified slightly
-   by Fyodor (fyodor () insecure org) */
-void lamont_hdump(char *cp, unsigned int length) {
 
-  /* stolen from tcpdump, then kludged extensively */
-
-  static const char asciify[] = "................................ 
!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~.................................................................................................................................";
-
-  const u_short *sp;
-  const u_char *ap;
-  unsigned char *bp = (unsigned char *) cp;
-  u_int i, j;
-  int nshorts, nshorts2;
-  int padding;
-  
-  log_write(LOG_PLAIN, "\n\t");
-  padding = 0;
-  sp = (u_short *)bp;
-  ap = (u_char *)bp;
-  nshorts = (u_int) length / sizeof(u_short);
-  nshorts2 = (u_int) length / sizeof(u_short);
-  i = 0;
-  j = 0;
-  while(1) {
-    while (--nshorts >= 0) {
-      log_write(LOG_PLAIN, " %04x", ntohs(*sp));
-      sp++;
-      if ((++i % 8) == 0)
-        break;
-    }
-    if (nshorts < 0) {
-      if ((length & 1) && (((i-1) % 8) != 0)) {
-        log_write(LOG_PLAIN, " %02x  ", *(u_char *)sp);
-        padding++;
-      }
-      nshorts = (8 - (nshorts2 - nshorts));
-      while(--nshorts >= 0) {
-        log_write(LOG_PLAIN, "     ");
-      }
-      if (!padding) log_write(LOG_PLAIN, "     ");
-    }
-    log_write(LOG_PLAIN, "  ");
-
-    while (--nshorts2 >= 0) {
-      log_write(LOG_PLAIN, "%c%c", asciify[*ap], asciify[*(ap+1)]);
-      ap += 2;
-      if ((++j % 8) == 0) {
-        log_write(LOG_PLAIN, "\n\t");
-        break;
-      }
-    }
-    if (nshorts2 < 0) {
-      if ((length & 1) && (((j-1) % 8) != 0)) {
-        log_write(LOG_PLAIN, "%c", asciify[*ap]);
-      }
-      break;
-    }
-  }
-  if ((length & 1) && (((i-1) % 8) == 0)) {
-    log_write(LOG_PLAIN, " %02x", *(u_char *)sp);
-    log_write(LOG_PLAIN, "                                       %c", asciify[*ap]);
-  }
-  log_write(LOG_PLAIN, "\n");
-}
-
 #ifndef HAVE_STRERROR
 char *strerror(int errnum) {
   static char buf[1024];
Index: tcpip.cc
===================================================================
--- tcpip.cc    (revision 15257)
+++ tcpip.cc    (working copy)
@@ -2223,7 +2223,7 @@
      fatal("FATAL: %s: bogus caplen from libpcap (%d) on interface type %d", __func__, head.caplen, datalink);
    } 
    error("FATAL:  Unknown datalink type (%d). Caplen: %d; Packet:", datalink, head.caplen);
-   lamont_hdump(p, head.caplen);
+   nmap_hexdump((unsigned char*)p, head.caplen);
    exit(1);
  }
 
Index: nmap_rpc.cc
===================================================================
--- nmap_rpc.cc (revision 15257)
+++ nmap_rpc.cc (working copy)
@@ -317,7 +317,7 @@
     /* Simply send this sucker we have created ... */
     do {  
       if (o.debugging > 1)
-       hdump((unsigned char *) rpch, sizeof(struct rpc_hdr));
+         nmap_hexdump((unsigned char *) rpch, sizeof(struct rpc_hdr));
       res = sendto(udp_rpc_socket, (char *)rpch, sizeof(struct rpc_hdr), 0,
                   (struct sockaddr *) &sock, socklen);
       if (res == -1)
Index: scan_engine.cc
===================================================================
--- scan_engine.cc      (revision 15257)
+++ scan_engine.cc      (working copy)
@@ -4264,9 +4264,9 @@
            break;
 
          default:
-           error("Unexpected ICMP type/code 3/%d unreachable packet:", 
+           error("Unexpected ICMP type/code 3/%d unreachable packet:\n", 
                  icmp->icmp_code);
-           hdump((unsigned char *)icmp, ntohs(ip->ip_len) - 
+             nmap_hexdump((unsigned char *)icmp, ntohs(ip->ip_len) - 
                  sizeof(struct ip));
            break;
          }

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

Current thread: