C 传递特殊字符作为参数
我需要将一个十六进制为C 传递特殊字符作为参数,c,bash,C,Bash,我需要将一个十六进制为002C0021的字符串作为命令行参数传递给我的程序,这是我无法做到的 #include<stdio.h> int main(int argc,char* argv[]){ // argv[1] should have the string that the above hex represents //... the program will use that string inside the program //...also please exp
002C0021
的字符串作为命令行参数传递给我的程序,这是我无法做到的
#include<stdio.h>
int main(int argc,char* argv[]){
// argv[1] should have the string that the above hex represents
//... the program will use that string inside the program
//...also please explain what should i do if i (am/am not) allowed to modify the source
}
您应该让您的程序接受包含转义符的字符串,并自己解析它们。因此,可以这样调用它:
$ ./myprogram '\x00\x2c\x00\x21'
例如(\x
与C本身使用的内容相匹配,因此用户可能很熟悉)。单引号是为了保护反斜杠不受shell的影响,不是100%确定,也不是在正确的提示下
结果不会是字符串,因为C中的字符串不能包含0个字符
下面是一个示例,展示了这一点:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static size_t decode(void *buf, size_t buf_max, const char *s)
{
unsigned char *put = buf;
unsigned char * const put_max = put + buf_max;
while (*s != '\0' && put != put_max)
{
if (*s == '\\')
{
++s;
if (*s == '\\')
*put++ = *s++;
else if (*s == 'x')
{
++s;
char *endp;
const unsigned long v = strtoul(s, &endp, 16);
if (endp == s)
break;
*put++ = (unsigned char) v;
s = endp;
}
else
break;
}
else
*put++ = *s++;
}
return put - (unsigned char *) buf;
}
int main(int argc, char *argv[])
{
unsigned char buf[32];
const size_t len = decode(buf, sizeof buf, "\\x0hello\\x1\\xaa\\xfe\\xed");
for (size_t i = 0; i < len; ++i)
{
printf("%x\n", buf[i]);
}
return 0;
}
#包括
#包括
#包括
静态大小解码(void*buf,size\t buf\u max,const char*s)
{
无符号字符*put=buf;
无符号字符*const put_max=put+buf_max;
而(*s!='\0'&&put!=put\u max)
{
如果(*s=='\\')
{
++s;
如果(*s=='\\')
*put++=*s++;
如果(*s=='x',则为else
{
++s;
char*endp;
常量无符号长v=strtoul(s和endp,16);
如果(endp==s)
打破
*put++=(无符号字符)v;
s=endp;
}
其他的
打破
}
其他的
*put++=*s++;
}
返回put-(unsigned char*)buf;
}
int main(int argc,char*argv[])
{
无符号字符buf[32];
const size_t len=decode(buf,sizeof buf,“\\x0hello\\x1\\xaa\\xfe\\xed”);
对于(尺寸i=0;i
请注意,
main()
中的测试“driver”将在您的情况下被替换,您希望将例如argv[1]
传递到decode()
。双反斜杠保护了C编译器,我们真的希望得到一个包含反斜杠转义的字符串。使用bash或任何其他shell都不可能将零字节传递给程序参数。这只是因为在C标准中是不可能的
C标准说明(强调矿山):
。。。主功能的参数应遵守以下约束:-…
-如果argc的值大于零,则数组成员argv[0]到argv[argc-1]应包含指向字符串的指针,这些字符串在程序启动之前由主机环境给定实现定义的值
- “字符串”是(强调我的): 字符串是以结尾的连续字符序列,包括第一个空字符。。。字符串的长度是空字符前面的字节数,字符串的值是包含字符的值的顺序 “空字符”是所有位都设置为0的
字节。它是零。字符串在第一个“空字符”处终止。如果一个字符数组中嵌入了零字节,那么它就不能是字符串(嘿,确切地说,请参见,字符串文字可能不是字符串,因为它可以嵌入空字符)。不能将参数中嵌入的多个0x00
值传递给C程序,因为传递的不是“字符串”
正确的方法是围绕它编写自己的解析器,它将接受“字符串”(即/a.out“002C0021”
)并自己转换为零字节
对于您的用例,如果它很简单,我可以在另一个答案中给出一个更简单的解析器。例如,您可以在程序中传递一个所有字节都递增1,然后递减1的参数
或者您可以传递特殊的字节值,比如ex.0xff
(如果您的实现和操作系统及环境支持传递0xff
字节),以代替0x00
,并在程序中替换它们。该选项如下所示:
#include <string.h>
#include <stddef.h>
#include <assert.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
assert(argc >= 2);
for (size_t i = 0, max = strlen(argv[1]); i < max; ++i) {
// replace all 0xff by 0x00
if ( (0xff & argv[1][i]) == 0xff) {
argv[1][i] = 0x00;
}
}
// use argv[1]
for (size_t i = 0, max = 4; i < max; ++i) {
printf("argv[1][%d] = 0x%02x\n", i, 0xff & argv[1][i]);
}
}
经过测试
bash将$'…'
解释为。\xff
被解释为十六进制常量,因此第一个参数将等于(char[]){0xff,0x2c,0xff,0x2c,0x00}
。用0x00
替换0xff
后,它将变成(char[]){0x00,0x2c,0x00,0x2c,0x00}
并且可以使用前4个字节。这个字符串应该被编码为UTF-16还是类似的东西?它肯定不是以\0
结尾的C字符串。如果您在Windows上工作,那么在命令行上支持宽字符的解决方案是使用int-wmain(int-argc,wchar\u t*argv[])
您需要将字节序列作为参数传递,还是让程序从标准输入读取它?对于后者,您可以执行/a.out是的,我需要将字节序列作为参数传递。这就是类似的事情的用途:使用受限字符集对任意二进制数据进行编码。即使您可以使用$“…”
语法和智能转义在bash命令行上以字符串形式传递几乎任意字节,这有其局限性。特别是,bash的内部字符串表示不能处理零字节(因为bash的C字符串零终止)。您永远不能将零字节从bash传递到任何地方,因为bash不像许多命令行工具那样在内部“允许”零字节。最好使用printf
(和consort)生成零并将它们直接导入程序。对于bash,它应该是/myprogram$'\x00\x2c\x00\x21'
。那么就不需要解析了。@alk-Uh,但是字符串中不能有0个字符,所以argv[1]
的值非常奇怪。它不是字符串数据,必须由应用程序从外部字符串表示形式解析。刚刚测试了这个,结果我给出了错误的建议,就像每次传递$'\x00\x2c\x00\x21'
时一样
#include <string.h>
#include <stddef.h>
#include <assert.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
assert(argc >= 2);
for (size_t i = 0, max = strlen(argv[1]); i < max; ++i) {
// replace all 0xff by 0x00
if ( (0xff & argv[1][i]) == 0xff) {
argv[1][i] = 0x00;
}
}
// use argv[1]
for (size_t i = 0, max = 4; i < max; ++i) {
printf("argv[1][%d] = 0x%02x\n", i, 0xff & argv[1][i]);
}
}
./a.out $'\xff\x2c\xff\x2c'