UUENCODE編解碼

uuencode解碼步驟

uuencode是以前unix下常用編碼方式應用於UUCP(unix to unix copy),通過串行通訊傳
輸二進制文件.base64屬於MIME(多用途國際互聯網
郵件擴展)編碼,與uuencode不是同一個範疇的,MIME主要應用於郵件,Uuencode主要應用
在郵件和新聞組.
uuencode的開頭是:
begin <模式> <文件名>
<數據>
end
編碼算法爲不斷地用3個字節數據列成一組(不足3個字節以零補齊)然後 此24位數據分
爲4 組,每組6位,再將得到的6位二進制數映射到ASCII碼32~95之間的字符,而每行以M 開頭(表示32+45),60個字符一行(包括”M”),最後一行以32+N 的ASCII字符開頭,N 爲最後一行編碼的輸入字節數.編碼以一個只含一個空格的一行和只含”end”的一行結束.

從前一部分看和base64沒有什麼區別(關於base64的編碼和解碼請參見http://www.csdn.net/develop/read_article.asp?id=8843),都是將3個字符換成4個字符,不同的是base64由自己的base64碼錶,而uuencode是直接使用ascii碼做碼錶.

eg.
begin .....
M1&%T93H(“’@(“’@(#0O-2’/Y-2’Y.C,S.C$P($%-#0I&<FJM.B’@(“’@(“’@
M2&5N<GDL($@N62X@5VJN9PT*4W5B:F5C=#H@(“’@($%B;W5T($U)344@96YC
M;VIE=VIE8V1E8VJD92!P<FJG<F%M#0I4;SH @(“’@(“’@(“’@0VAA<FQE<R!-80T*
M;W(@8F%S938T(‘1R86YS9F5R(&9O<FUA=”P-“B’ @(“’@(“’@(“’@(“UO(#QF
end

這裏以Attacking the Core : Kernel Exploiting Notes爲例。
將文章末尾的

begin 644 stuff.tgz
M'XL(`!J,'T8``^P/^W/;-M+Y59KI_X!1&X>2Y8B49-FQZLRHL=SXXM?XD;87
M9S@4"=H/4Z1*4H[<-/>WW^X")___FCKpd___0amp;*=I*>D]XW7]C:)@'LXK$/["X6B9.YZW8>
M?=%'AV=C?1W_&AOK.GT;_3[]E</C0Q_HW6Y77Q]T'^E&M[?>?/36O^RPQ#./
M$RMB[%'RSOOC_G8/BN^I3R>2_OT_/L1$?[Z8^5^."3Z'_EV]!_3O]8QO]//J
。。。。。。
M^QLZ*/YN[[NC_K?/,--UL&OHC!K0UB`>WC`.<.3+B_R7#T9PU/G"1:F1VJ4J
M&(GAW^!E@J!JS,*8C9RWUT4)>HIWSI4%(^JR<;I7$VY`BP'9,M*V;GY7QEA4
M<M/Z>]_&>'Z>G^?G^7E^GI_GY_EY?IZ?Y^?Y>7Z>G^?G^7E^GI_GY_EY?IZ?
HY^?Y>7Z>G^?G^7E^GI_GY_EY?IZ?Y^?Y>7Z>G/<]_Q=OV)(^``@"````
`
end

拷貝到一個文本當中去,這裏取名爲1
wangyao@netkite:~/Desktop$ uudecode 1
這時候,目錄下面就會有一個stuff.tar.gz,就是代碼了。

同樣還有一種是base64編碼的,例如Hacking Grub for fun and profit
後面的代碼是經過base64編碼過的,其形式稍微有所不同。
begin-base64 644 hack_grub.tar.gz
H4sIADW+x0IAA+19a49kSXZQ7i6wZK1tbEAyHxCKqZnuyczKqsrMenRN5XTv
VldXz9ZOd1W7q3p27J7m7q3Mm1V3Ol99b2Z318w2QgjxwQghIRkLI9viAxL8
......
4lehcOHQYYVXF7eskBcbrfAyEdcKLxHqrfDqIs7lVG726HeFlwq+5+R++UiA
SaZOiEFYeKlghxct6PLxG/NKshC/TNxJjWTGYJeFlwisWXipkJ5vWzHNr/k1
v+bX/Jpf82t+za/5Nb/m1/yaX/PrDVz/H1KGin8AGAEA
====
它不是以end結尾的。
解碼步驟跟上面一樣。

===== 編碼 =====
uu 編碼

uuencode 編碼方式用於將任意的二進制文件轉換爲文本文件,比如email.轉換後的文件中僅包含可打印字符.
uuencode 運算法則將連續的 3字節編碼轉換成 4字節(8-bit 到 6-bit)的可打印字符. 該編碼的效率高於Hex 格式

從二進制文件中讀取 3字節的數據, 表示如下(a7 表示 a字節的第 7位):
  a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0
轉換它們到4字節裏爲如下所示:
  0 0 a7a6a5a4a3a2 0 0 a1a0b7b6b5b4 0 0 b3b2b1b0c7c6 0 0 c5c4c3c2c1c0
然後, 每個字節再加 0x20轉換爲可打印的字符.
注意: 如果是一個 0字節那它應該被轉換爲0x60而不是0x20, 因爲(前引用'`')優於 0x20(空格' ').

例如: 從文件中讀取的 3字節如下:
        14       0F       A8
  00010100 00001111 10101000
轉換爲 6-bit:
  000101 000000 111110 101000
每字節高兩位補 0後爲:
  00000101 00000000 00111110 00101000
最後每字節再加 0x20,則 4字節輸出應該爲:
  25 60 5E 48
注意: 00字節被轉換爲 0x60而不是 0x20.

因此, 在一個 uuencoded文件中僅包含字符 0x21 '!'到 0x60 '`',它們都是可打印和可被 email傳送的.
這個轉換過程也意味着 uuencoded 文件要比原文件大 33%的.

outbuf  [4] 輸出 uu編碼數據.
inbytep [3] 輸入二進制數據.

#define ENCODE_BYTE(b) (((b) == 0) ? 0x60 : ((b) + 0x20))
    outbuf [0] = ENCODE_BYTE  ((inbytep [0] & 0xFC) >> 2);
    outbuf [1] = ENCODE_BYTE (((inbytep [0] & 0x03) << 4) +
                              ((inbytep [1] & 0xF0) >> 4));
    outbuf [2] = ENCODE_BYTE (((inbytep [1] & 0x0F) << 2) +
                              ((inbytep [2] & 0xC0) >> 6));
    outbuf [3] = ENCODE_BYTE   (inbytep [2] & 0x3F);

===== 解碼 =====
linep [4]   輸入 uu編碼數據.
outbyte [3] 輸出二進制數據.

#define DECODE_BYTE(b) ((b == 0x60) ? 0 : b - 0x20)
      outbyte [0] = DECODE_BYTE (linep [0]);
      outbyte [1] = DECODE_BYTE (linep [1]);
      outbyte [0] <<= 2;
      outbyte [0] |= (outbyte [1] >> 4) & 0x03;
      outbyte [1] <<= 4;
      outbyte [2] = DECODE_BYTE (linep [2]);
      outbyte [1] |= (outbyte [2] >> 2) & 0x0F;
      outbyte [2] <<= 6;
      outbyte [2] |= DECODE_BYTE (linep [3]) & 0x3F;

詳細描述見 http://www.wotsit.org
// 結束.

 

 

我的編碼函數

//sample code

#define MAX_LINELEN 45
#define ENCODE_BYTE(b) (((b) == 0) ? 0x60 : ((b) + 0x20))
int UUEnocde(const char *pSrc, char *pDest,unsigned long ulLen)
{
 int linelen;
 int linecnt;
 BYTE inbuf [MAX_LINELEN];
 BYTE *inbytep;
 char outbuf [5];
 int offset = 0;
 int iLast  = 0;
 
 do
 {  
  if(ulLen > MAX_LINELEN)
  {
   linelen = MAX_LINELEN;
   ulLen -= MAX_LINELEN;
  }
  else
  {
   //即將退出循環
   linelen = ulLen;
   iLast = 1;
  }
  
  memcpy(inbuf, pSrc, linelen);
  
  /* Write the line length byte */
  
  memset(pDest + offset,ENCODE_BYTE (linelen),  1);
  offset += 1;
  
  /* Encode the line */
  
  for (linecnt = linelen, inbytep = inbuf;
  linecnt > 0;
  linecnt -= 3, inbytep += 3)
  {
   
   /* Encode 3 bytes from the input buffer */
   
   outbuf [0] = ENCODE_BYTE ((inbytep [0] & 0xFC) >> 2);
   outbuf [1] = ENCODE_BYTE (((inbytep [0] & 0x03) << 4) +
    ((inbytep [1] & 0xF0) >> 4));
   outbuf [2] = ENCODE_BYTE (((inbytep [1] & 0x0F) << 2) +
    ((inbytep [2] & 0xC0) >> 6));
   outbuf [3] = ENCODE_BYTE (inbytep [2] & 0x3F);
   outbuf [4] = '/0';
   
   /* Write the 4 encoded bytes to the file */
   
   memcpy (pDest + offset , outbuf,  strlen(outbuf));
   offset += strlen(outbuf);   
  }
  
  memcpy(pDest + offset, "/r/n", 2);
  offset += 2;
  
 } while ((linelen != 0) && !iLast);
 
 return 0;
}

 


 

 

 

 

我的解碼函數

//sample code

 

#define LINE_BUF_SIZE 62
#define UUDECODE_READ_SIZE 62
#define DECODE_BYTE(b) ((b == 0x60) ? 0 : b - 0x20) 

 

int UUDecode(const char *pSrc, long ulLen,  char*pDest)
{
 int  offset=0;    //轉換輸出偏移
 int  cpOffSet = 0;//拷貝偏移
 char linebuf[LINE_BUF_SIZE];
 char *linep = NULL;
 char *tempcp= NULL;                          
 int  linelen= 0;
 int  linecnt= 0;
 unsigned char outbyte[3]; 

 do
 {
  //每次都拷貝62字節
  //因爲編碼時取45字節轉成60並寫入分隔符2字節
  if(ulLen >= 0)
  {
   ulLen -= UUDECODE_READ_SIZE;   
  }
  else
  {
   break;
  }

  //取62Bytes
  memcpy(linebuf, pSrc + cpOffSet, UUDECODE_READ_SIZE);
  cpOffSet += UUDECODE_READ_SIZE;
  
  //解碼後長度
  linelen = DECODE_BYTE (linebuf [0]);
  linep = linebuf + 1;
  for (linecnt = linelen; linecnt > 0; linecnt -= 3, linep += 4)
  {
   outbyte [0] = DECODE_BYTE (linep [0]);
   outbyte [1] = DECODE_BYTE (linep [1]);
   outbyte [0] <<= 2;
   outbyte [0] |= (outbyte [1] >> 4) & 0x03;
   outbyte [1] <<= 4;
   outbyte [2] = DECODE_BYTE (linep [2]);
   outbyte [1] |= (outbyte [2] >> 2) & 0x0F;
   outbyte [2] <<= 6;
   outbyte [2] |= DECODE_BYTE (linep [3]) & 0x3F;
   
   //寫回Buffer
   if (linecnt > 3)
   {
    memcpy(pDest + offset,outbyte,3);
    offset += 3;
   }
   else
   {
    memcpy(pDest + offset,outbyte,linecnt);
    offset += linecnt;
    linecnt = 3;
   }   
  }
  
 } while (linelen != 0);

 //置結束標誌
 memset(pDest + offset, 0, 1 ); 

 return offset; 
}

 

Date: Wed, 09 Apr 1997 13:04:11 +0100
From: jim <[email protected]>
To: [email protected]

===== UUENCODE ======

uuencode is a utility designed to enable arbitrary binary files to be
transmitted using text-only media such as email. It does this by
encoding the files in such a way that the encoded file contains only
printable characters.

(IMPORTANT Note: this file is the result of an afternoon's hacking by
myself. I make no guarantees as to its completeness and accuracy. I have
coded my own uuencode and uudecode programs which haven't let me down
yet)

The uuencode algorithm hinges around a 3-byte-to-4-byte  (8-bit to 6-bit
data) encoding to convert all data to printable characters. To perform
this encoding read in 3 bytes from the file to be encoded whose binary
representation is

  a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0

and convert them into 4 bytes with values in the range 0-63 as follows:

  0 0 a7a6a5a4a3a2 0 0 a1a0b7b6b5b4 0 0 b3b2b1b0c7c6 0 0 c5c4c3c2c1c0

Then convert these bytes to printable characters by adding 0x20 (32).
EXCEPTION: if you end up with a zero byte it should be converted to 0x60
(back-quote '`') rather than 0x20 (space ' ').

So if you read 3 bytes from the file as follows: 14 0F A8 (hex) i.e.

  00010100 00001111 10101000

your 4 bytes output should be 25 60 5E 48 ("%`^H"). The intermediate 4
bytes in this case were

  00000101 00000000 00111110 00101000

Note that the zero byte has been translated to 0x60 instead of 0x20. The
body of a uuencoded file therefore only contains the characters 0x21 '!'
to 0x60 '`', which are all printable and capable of being transmitted by
email.
(Note: this of course means that uuencoded files are slightly more than
33% longer than the originals. uuencoding text-only files is redundant
and a silly thing to do. Standard and sensible practice is to compress
the files first using a standard compression utility and then to
uuencode them).

In addition, the start of the encoding is marked by the line "start
<mode> <filename>", where
  <mode> consists of 3 octal digits which are the Unix mode of the file,
and
  <filename> is the original filename of the file encoded.

The end of the encoding is marked by the line "end".

The first character of each line contains the line length in bytes *in
the original file*, encoded in the same way as an ordinary byte i.e.
line length 0->0x60, all other lengths add 0x20 to convert to printable
characters. Line lengths vary from 0 to 45 (which encodes to 'M'; this
is why lines in a uuencoded file all start with an M), which is a line
length of 61 characters (including the length character) in the encoded
file. This is a nice safe length to transmit via email.

Lines in the encoded file are always a multiple of 4 + 1 characters
long; this sometimes means that 1 or 2 bytes are thrown away at the end
of the decoding.

(Note: I can't see any reason why lines shouldn't be an arbitrary
length, and don't know whether the proper definition disallows this.
I've never seen a uuencoded file where any line apart from the last one
wasn't 'M' followed by 60 characters, though)

To decode, simply perform the inverse of the encoding algorithm.

===== SAMPLE CODE =====

I include here the C source code to a small uuencode and uudecode
utility I coded myself. It isn't very sophisticated and probably not
very complete, but it does its job, and is very useful for my PC where I
don't have access to the standard Unix stuff. It took me about half an
hour to write, and another hour or so to iron out the obvious bugs. It
works quite happily under DOS (uuencoding needs practically no internal
storage). It isn't a great masterpiece of software design and coding,
but might be worth a look. Feel free to do whatever you want to it, up
to and including throwing it in the bin.

===== uuencode.c =====

/*
 * uuencode.c -
 *  Simple uuencode utility
 *  Jim Cameron, 1997
 */

#include "stdio.h"
#include "stdlib.h"

#define MAX_LINELEN 45

#define ENCODE_BYTE(b) (((b) == 0) ? 0x60 : ((b) + 0x20))

typedef unsigned char BYTE;

int main (int argc, char *argv [])
{

  FILE *infile = NULL;
  FILE *outfile = NULL;
  int linelen;
  int linecnt;
  BYTE inbuf [MAX_LINELEN];
  BYTE *inbytep;
  char outbuf [5];

  if (argc != 3)
  {
    fprintf (stderr, "Syntax: uuencode <infile> <outfile>/n");
    exit (1);
  }

  /* Try and open the input file (binary) */

  infile = fopen (argv [1], "rb");
  if (infile == NULL)
  {
    fprintf (stderr, "uuencode: Couldn't open input file %s/n", argv
[1]);
    exit (1);
  }

  /* Try and open the output file (text) */

  outfile = fopen (argv [2], "wt");
  if (outfile == NULL)
  {
    fprintf (stderr, "uuencode: Couldn't open output file %s/n", argv
[2]);
    exit (1);
  }

  /* Write the 'begin' line, giving it a mode of 0600 */

  fprintf (outfile, "begin 600 %s/n", argv [1]);

  do
  {

    /* Read a line from input file */

    linelen = fread (inbuf, 1, MAX_LINELEN, infile);

    /* Write the line length byte */

    fputc (ENCODE_BYTE (linelen), outfile);

    /* Encode the line */

    for (linecnt = linelen, inbytep = inbuf;
         linecnt > 0;
         linecnt -= 3, inbytep += 3)
    {

      /* Encode 3 bytes from the input buffer */

      outbuf [0] = ENCODE_BYTE ((inbytep [0] & 0xFC) >> 2);
      outbuf [1] = ENCODE_BYTE (((inbytep [0] & 0x03) << 4) +
                                ((inbytep [1] & 0xF0) >> 4));
      outbuf [2] = ENCODE_BYTE (((inbytep [1] & 0x0F) << 2) +
                                ((inbytep [2] & 0xC0) >> 6));
      outbuf [3] = ENCODE_BYTE (inbytep [2] & 0x3F);
      outbuf [4] = '/0';

      /* Write the 4 encoded bytes to the file */

      fprintf (outfile, "%s", outbuf);

    }

    fprintf (outfile, "/n");

  } while (linelen != 0);

  /* Write the 'end' marker */

  fprintf (outfile, "end/n");

  /* Tidy up and return */

  fclose (infile);
  fclose (outfile);

  return 0;

}

===== uudecode.c =====

/*
 * uudecode.c -
 *  Simple uudecode utility
 *  Jim Cameron, 1997
 */

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

/* We all hate magic numbers! */

#define LINE_BUF_SIZE 256

/* Decode a byte */

#define DECODE_BYTE(b) ((b == 0x60) ? 0 : b - 0x20)

typedef unsigned char BYTE;

int main (int argc, char *argv [])
{

  FILE *infile = NULL;
  FILE *outfile = NULL;
  char linebuf [LINE_BUF_SIZE];
  char *linep = NULL;
  char *tempcp = NULL;                          
  int   linelen = 0;
  int   linecnt = 0;
  char outfname [LINE_BUF_SIZE];
  BYTE outbyte [3];

  /* Check that we have the right number of arguments */

  if (argc != 2)
  {
    fprintf (stderr, "Syntax: uudecode <filename>/n");
    exit (1);
  }

  /* Open the input file */

  infile = fopen (argv [1], "rt");
  if (infile == NULL)
  {
    fprintf (stderr, "uudecode: Couldn't open file %s/n", argv [1]);
    exit (1);
  }

  /* uu-encoded files always have a 'begin' marker, so go and look for
this */

  for (;;)
  {

    /* Read a line */

    if (fgets (linebuf, LINE_BUF_SIZE, infile) == NULL)
    {
      fprintf (stderr, "uudecode: Not a valid uu-encoded file/n");
      exit (1);
    }

    /* See if it is the 'begin' marker */

    if ((strncmp (linebuf, "begin", 5) == 0) && isspace (linebuf [5]))
    {
      break;
    }

  }

  /* If we have reached this point, we have found a begin marker */

  linep = linebuf + 5;

  /* Next comes the mode, which we ignore */

  while (isspace (*linep))
  {
    linep++;
  }
  if (*linep == '/0')
  {
    fprintf (stderr, "uudecode: Not a valid uu-encoded file/n");
    exit (1);
  }

  while (isdigit (*linep))
  {
    linep++;
  }
  while (isspace (*linep))
  {
    linep++;
  }
  if (*linep == '/0')
  {
   fprintf (stderr, "uudecode: Not a valid uu-encoded file/n");
    exit (1);
  }

  /* The rest of the begin line is the output file name */

  strcpy (outfname, linep);
  tempcp = outfname;
  while (!isspace (*tempcp) && (*tempcp != '/0'))
  {
    tempcp++;
  }
  *tempcp = '/0';

  /* Now open the output file */

  outfile = fopen (outfname, "wb");
  if (outfile == NULL)
  {
    fprintf (stderr, "uudecode: Couldn't open output file %s/n",
outfname);
    exit (1);
  }

  /* Now for the uu-decode proper */

  do
  {

    if (fgets (linebuf, LINE_BUF_SIZE, infile) == NULL)
    {
      fprintf (stderr, "uudecode: Read error/n");
      exit (1);
    }

    /* The first byte of the line represents the length of the DECODED
line */

    linelen = DECODE_BYTE (linebuf [0]);
    linep = linebuf + 1;
    for (linecnt = linelen; linecnt > 0; linecnt -= 3, linep += 4)
    {

      /* Check for premature end-of-line */

      if ((linep [0] == '/0') || (linep [1] == '/0') ||
          (linep [2] == '/0') || (linep [3] == '/0'))
      {
       fprintf (stderr, "uudecode: Error in encoded block/n");
 exit (1);
      }

      /* Decode the 4-byte block */

      outbyte [0] = DECODE_BYTE (linep [0]);
      outbyte [1] = DECODE_BYTE (linep [1]);
      outbyte [0] <<= 2;
      outbyte [0] |= (outbyte [1] >> 4) & 0x03;
      outbyte [1] <<= 4;
      outbyte [2] = DECODE_BYTE (linep [2]);
      outbyte [1] |= (outbyte [2] >> 2) & 0x0F;
      outbyte [2] <<= 6;
      outbyte [2] |= DECODE_BYTE (linep [3]) & 0x3F;

      /* Write the decoded bytes to the output file */

      if (linecnt > 3)
      {
 if (fwrite (outbyte, 1, 3, outfile) != 3)
 {
   fprintf (stderr, "uudecode: Error writing to output file/n");
         exit (1);
 }
      }
      else
      {
       if (fwrite (outbyte, 1, linecnt, outfile) != linecnt)
        {
   fprintf (stderr, "uudecode: Error writing to output file/n");
          exit (1);
        }
        linecnt = 3;
      }

    }

  } while (linelen != 0);

  /* All is ok, tidy up and exit */

  fclose (infile);
  fclose (outfile);

  return 0;

}

===== end =====
 
jim
--
[email protected]
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章