diff --git a/src/urclock.c b/src/urclock.c
index c66c616e..2fb31558 100644
--- a/src/urclock.c
+++ b/src/urclock.c
@@ -263,7 +263,9 @@ typedef struct {
       vbllevel,                 // 0=n/a, 1=patch externally, 2=bl patches, 3=bl patches & verifies
       blurversion,              // Octal byte 076 means v7.6 (minor version number is lowest 3 bit)
                                 // Small numbers < 070 probably are optiboot major version number
-      bloptiversion;            // Optiboot version as (major<<8) + minor
+      bloptiversion,            // Optiboot version as (major<<8) + minor
+      blguessed;                // Guessed the bootloader from hash data
+
   int32_t blstart;              // Bootloader start address, eg, for bootloader write protection
 
   int idmchr;                   // Either 'E' or 'F' for the memory where the Urclock ID is located
@@ -940,7 +942,7 @@ nopatch_nometa:
 
 
 // Put version string into a buffer of max 19 characters incl nul (normally 15-16 bytes incl nul)
-static void urbootPutVersion(char *buf, uint16_t ver, uint16_t rjmpwp) {
+static void urbootPutVersion(const PROGRAMMER *pgm, char *buf, uint16_t ver, uint16_t rjmpwp) {
   uint8_t hi = ver>>8, type = ver & 0xff, flags;
 
   if(ver == 0xffff)             // Unknown provenance
@@ -968,9 +970,11 @@ static void urbootPutVersion(char *buf, uint16_t ver, uint16_t rjmpwp) {
     *buf++ = hi >= 077 && (type & UR_AUTOBAUD)? 'a': '-';                 // - means no
     *buf++ = hi >= 077 && (type & UR_HAS_CE)? 'c': hi >= 077? '-': '.';   // . means don't know
     *buf = 0;
-  } else if(hi)                 // Version number in binary from optiboot v4.1
-    sprintf(buf, "o%d.%d -?s-?-r--", hi, type);
-  else
+  } else if(hi) {               // Version number in binary from optiboot v4.1
+    sprintf(buf, "o%d.%d -%cs-%c-r--", hi, type,
+      ur.blguessed? (ur.bleepromrw? 'e': '-'): '?',
+      ur.blguessed? "hjvV"[ur.vbllevel & 3]: '?');
+  } else
     sprintf(buf, "x0.0 .........");
 
   return;
@@ -1096,6 +1100,107 @@ static void set_uP(const PROGRAMMER *pgm, const AVRPART *p, int mcuid, int mcuid
 }
 
 
+// https://en.wikipedia.org/wiki/Jenkins_hash_function
+static uint32_t jenkins_hash(const uint8_t* key, size_t length) {
+  size_t i = 0;
+  uint32_t hash = 0;
+
+  while (i != length) {
+    hash += key[i++];
+    hash += hash << 10;
+    hash ^= hash >> 6;
+  }
+  hash += hash << 3;
+  hash ^= hash >> 11;
+  hash += hash << 15;
+
+  return hash;
+}
+
+typedef struct {
+  uint16_t sz, ee;
+  uint32_t h256, hash;
+} Blhash_t;
+
+static int cmpblhash(const void *va, const void *vb) {
+  const Blhash_t *a = va, *b = vb;
+  return a->sz > b->sz? 1: a->sz < b->sz? -1: a->hash > b->hash? 1: a->hash < b->hash? -1: 0;
+}
+
+static void guessblstart(const PROGRAMMER *pgm, const AVRPART *p) {
+  if(ur.urprotocol && !(ur.urfeatures & UB_READ_FLASH)) // Cannot read flash
+    return;
+
+  Blhash_t blist[] = {
+    { 1024, 0, 0x35445c45, 0x9ef77953 }, // ATmegaBOOT-prod-firmware-2009-11-07.hex
+    { 1024, 0, 0x32b1376c, 0xceba80bb }, // ATmegaBOOT.hex
+    { 2048, 0, 0x08426ba2, 0x29e81e21 }, // ATmegaBOOT_168.hex
+    { 4096, 0, 0x1bf8ed1b, 0x272e49ed }, // ATmegaBOOT_168_atmega1280.hex
+    { 2048, 0, 0x9774b926, 0x335016ed }, // ATmegaBOOT_168_atmega328.hex
+    { 4096, 0, 0x3242ddd3, 0x809632a3 }, // ATmegaBOOT_168_atmega328_bt.hex
+    { 2048, 0, 0xc553f5b4, 0x56be91cb }, // ATmegaBOOT_168_atmega328_pro_8MHz.hex
+    { 2048, 0, 0x12ab8da0, 0xca46a3ca }, // ATmegaBOOT_168_diecimila.hex
+    { 2048, 0, 0x3242ddd3, 0xf3e94dba }, // ATmegaBOOT_168_ng.hex
+    { 2048, 0, 0x2eed30b3, 0x47d14ffa }, // ATmegaBOOT_168_pro_8MHz.hex
+    { 4096, 0, 0xc52edd05, 0xa3371f94 }, // Caterina-LilyPadUSB.hex
+    { 4096, 0, 0x663b8f7e, 0x7efdda2b }, // Caterina-Robot-Control.hex
+    { 4096, 0, 0x3c6387e7, 0x7e96eea2 }, // Caterina-Robot-Motor.hex
+    { 2048, 0, 0x1cef0d75, 0x6cfbac49 }, // LilyPadBOOT_168.hex
+    { 1024, 1, 0x6ca0f37b, 0x31bae545 }, // bigboot_328.hex
+    {  512, 0, 0x035cbc07, 0x24ba435e }, // optiboot_atmega168.hex
+    {  512, 0, 0x455050db, 0x1d53065f }, // optiboot_atmega328-Mini.hex
+    {  512, 0, 0xd2001ddb, 0x16c9663b }, // optiboot_atmega328.hex v4.4
+    {  512, 0, 0x49c1e9a4, 0xa450759b }, // optiboot_atmega328.hex v8.3
+    {  512, 0, 0xc54dcd6c, 0x5bfc5d06 }, // optiboot_atmega8.hex
+    {  256, 0, 0x5a01c55b, 0x5a01c55b }, // picobootArduino168.hex
+    {  256, 0, 0x1451061b, 0x1451061b }, // picobootArduino168v3b2.hex
+    {  512, 0, 0x3242ddd3, 0x53348738 }, // picobootArduino328.hex
+    {  512, 0, 0x858e12de, 0xc80a44a4 }, // picobootArduino328v3beta.hex
+    {  256, 0, 0xaa62bafc, 0xaa62bafc }, // picobootArduino8v3rc1.hex
+    {  256, 0, 0x56263965, 0x56263965 }, // picobootSTK500-168p.hex
+    {  512, 0, 0x3242ddd3, 0x5ba5f5f6 }, // picobootSTK500-328p.hex
+  };
+
+  uint8_t buf[4096], b128[128];
+
+  qsort(blist, sizeof blist/sizeof*blist, sizeof*blist, cmpblhash);
+  for(int ii, si = 0, sz = 0, bi = 0; si < (int) sizeof blist/sizeof*blist; si++) {
+    if(blist[si].sz > sz) { // Read in and compare
+      sz = blist[si].sz;
+      if(sz > ur.uP.flashsize/2 || (sz+127)/128*128 > (int) sizeof buf)
+        return;
+      while(bi < sz) {
+       if(ur_readEF(pgm, p, b128, ur.uP.flashsize-bi-128, 128, 'F') < 0)
+         return;
+       for(int ti=127; ti >= 0; ti--) // read in backwards
+         buf[bi++] = b128[ti];
+      }
+
+      // Does the hash for the full size match? OK: found a known bootloader
+      uint32_t hash = jenkins_hash(buf, sz);
+      for(ii = 0; ii < (int) sizeof blist/sizeof*blist; ii++)
+        if(blist[ii].hash == hash && sz == blist[ii].sz && !(sz & (ur.uP.pagesize-1))) {
+          // Page aligned bootloader size matches
+          ur.blstart = ur.uP.flashsize-sz;
+          if(blist[ii].ee)
+            ur.bleepromrw = 1;
+          ur.blguessed = 1;
+          return;
+        }
+
+      // Can we exclude the top 256 byte flash from the botloader list?
+      if(sz == 256) {
+        for(ii = 0; ii < (int) sizeof blist/sizeof*blist; ii++)
+          if(hash == blist[ii].h256)
+            break;
+        if(ii >= (int) sizeof blist/sizeof*blist)
+          return;
+      }
+    }
+  }
+}
+
+
 /*
  * Read signature bytes - Urclock version
  *
@@ -1242,8 +1347,8 @@ static int ur_initstruct(const PROGRAMMER *pgm, const AVRPART *p) {
     uint8_t urver = spc[5];     // Urboot version (low three bits are minor version: 076 is v7.6)
     v16 = buf2uint16(spc+4);    // Combo word for neatly printed version line of urboot bootloader
 
-    // Extensively check this is an urboot bootloader, and if OK extract properties
-    if(urver >= 072 && urver != 0xff && (isRjmp(rjmpwp) || rjmpwp == ret_opcode)) { // Prob urboot
+    // Extensively check this is an urboot bootloader v7.2 .. v12.7 == 0147 and extract properties
+    if(urver >= 072 && urver <= 0147 && (isRjmp(rjmpwp) || rjmpwp == ret_opcode)) { // Prob urboot
       ur.blurversion = urver;
       ur.bleepromrw = iseeprom_cap(cap);
       // Vector bootloader: 0 = none, 1 = external patching, 2 = bl patches, 3 = patches + verifies
@@ -1281,11 +1386,9 @@ static int ur_initstruct(const PROGRAMMER *pgm, const AVRPART *p) {
       }
     } else if(urver != 0xff) {  // Probably optiboot where the version number is two bytes
       ur.bloptiversion = (urver<<8) + cap;
-      if(!ur.blstart)
-        Return("bootloader might be optiboot %d.%d? Please use -xbootsize=<num>\n", urver, cap);
     }
 
-    if(!ur.blstart && ur.vbllevel) { // An older version urboot vector bootloader
+    if(!ur.blstart && ur.vbllevel) { // An older version urboot vector bootloader?
       int vecsz = ur.uP.flashsize <= 8192? 2: 4;
 
        // Reset vector points to the bootloader and the bootloader has r/jmp to application?
@@ -1356,13 +1459,21 @@ static int ur_initstruct(const PROGRAMMER *pgm, const AVRPART *p) {
       }
     }
 
-    // Still no bootloader start address?
+    // Still no bootloader start address? Read in top flash and guess bootloader start
     if(!ur.blstart)
+      guessblstart(pgm, p);
+
+    // Still no bootloader start address?
+    if(!ur.blstart) {
+      if(ur. bloptiversion)
+       Return("bootloader might be optiboot %d.%d? Please use -xbootsize=<num>\n",
+         ur.bloptiversion>>8, ur.bloptiversion & 255);
       Return("unknown bootloader ... please specify -xbootsize=<num>\n");
+    }
   }
 
 vblvecfound:
-  urbootPutVersion(ur.desc, v16, rjmpwp);
+  urbootPutVersion(pgm, ur.desc, v16, rjmpwp);
 
   ur.mcode = 0xff;
   if(ur.blstart) {