UUENCODE编解码

C/C++语言问题 专栏收录该内容
47 篇文章 0 订阅

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结尾的。
解码步骤跟上面一样。

uuencode编码的原理
参考:
http://blog.21ic.com/user1/1575/archives/2005/5608.html
===== 编码 =====
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 <j.cameron@physiology.ucl.ac.uk>
To: webmaster@wotsit.demon.co.uk

===== 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
--
j.cameron@physiology.ucl.ac.uk
 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页

打赏作者

飞哥

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值