[Windows Mobile Development and Hacking General] mamaich:
The most recent ROM update released by Dopod has changed the format of NBF files. Here is the information I've found. Maybe someone would create a new xda3nbftool from the code I provide? I don't have time for this. Probably the same format soon would be used in other operator's updates.

New NBF files header is normally 0xAB bytes in length and looks like "K7qAW73q39..skipped..t7=". It is a base64 encoded string with a modified alphabet. The string length may change in the newer version, so you need to search for "=" to find the end of a header.

Here is a sample code that decodes it:

/*
* $Id: base64.c,v 1.1.1.1 2001/10/04 00:16:06 andrewr Exp $
* modified by mamaich for HTC firmware
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static void base64_init(void);

static int base64_initialized = 0;
#define BASE64_VALUE_SZ 256
#define BASE64_RESULT_SZ 8192
int base64_value[BASE64_VALUE_SZ];

/*
* This is the original base64 decode table:
*
const char* base64_code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
*/

/*
* BaUpgradeUt uses a modified alphabet:
*/
const char* base64_code = "yz98765432UVWXYZabcdKLMNOPQRSTopqrstuvwxefghijklmnABCDEFGHIJ10+/";

static void
base64_init(void)
{
int i;

for (i = 0; i < BASE64_VALUE_SZ; i++)
base64_value[i] = -1;

for (i = 0; i < 64; i++)
base64_value[(int) base64_code[i]] = i;
base64_value['='] = 0;

base64_initialized = 1;
}

char *
base64_decode(const char *p)
{
static char result[BASE64_RESULT_SZ];
int j;
int c;
long val;
if (!p)
return NULL;
if (!base64_initialized)
base64_init();
val = c = 0;
for (j = 0; *p && j + 4 < BASE64_RESULT_SZ; p++) {
unsigned int k = ((unsigned char) *p) % BASE64_VALUE_SZ;
if (base64_value[k] < 0)
continue;
val <<= 6;
val += base64_value[k];
if (++c < 4)
continue;
/* One quantum of four encoding characters/24 bit */
result[j++] = val >> 16;	/* High 8 bits */
result[j++] = (val >> 8) & 0xff;	/* Mid 8 bits */
result[j++] = val & 0xff;	/* Low 8 bits */
val = c = 0;
}
result[j] = 0;
return result;
}

/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
const char *
base64_encode(const char *decoded_str)
{
static char result[BASE64_RESULT_SZ];
int bits = 0;
int char_count = 0;
int out_cnt = 0;
int c;

if (!decoded_str)
return decoded_str;

if (!base64_initialized)
base64_init();

while ((c = (unsigned char) *decoded_str++) && out_cnt < sizeof(result) - 5) {
bits += c;
char_count++;
if (char_count == 3) {
result[out_cnt++] = base64_code[bits >> 18];
result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
result[out_cnt++] = base64_code[bits & 0x3f];
bits = 0;
char_count = 0;
} else {
bits <<= 8;
}
}
if (char_count != 0) {
bits <<= 16 - (8 * char_count);
result[out_cnt++] = base64_code[bits >> 18];
result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
if (char_count == 1) {
result[out_cnt++] = '=';
result[out_cnt++] = '=';
} else {
result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
result[out_cnt++] = '=';
}
}
result[out_cnt] = '\0';	/* terminate */
return result;
}

int main()
{
char *In="K7qAW73q39yq39yq39yq37bZK707Xtyn39yq39yq39zNLCKq39yq387kWtakW8Oq39yq39yq39z9R4LvaMHxPMmq39yq39yqW9yq39yq39zrW8ymW8ymW8amW8ym39yq39yq39yq39yq39yq39yq39yq39yq39yqW5KEY8qAWt7=";
puts(base64_decode(In));
}