我的问题是我不懂一行代码
当这个envp参数出现在main上时,我正在反向工程一个crackme,然后程序开始使用它,这使我不明白如何解决crackme的第二部分(我使用c反编译程序来分析crackme的密码)。我仍然用修补二进制代码解决了crackme问题,但我不明白这一行的意思,它正在困扰我。。。。
int __cdecl main(int argc, const char **argv, const char **envp){
char *Format; // [esp+0h] [ebp-98h]
char v5; // [esp+20h] [ebp-78h]
_alloca((size_t)Format);
__main();
printf("IOLI Crackme Level 0x06\n");
printf("Password: ");
scanf("%s", &v5);
check(&v5, (int)envp);
return 0;
}
int __cdecl check(char *Str, int a2){
size_t v2; // eax
char Src; // [esp+1Bh] [ebp-Dh]
unsigned int i; // [esp+1Ch] [ebp-Ch]
int v6; // [esp+20h] [ebp-8h]
int v7; // [esp+24h] [ebp-4h]
v6 = 0;
for ( i = 0; ; ++i ){
v2 = strlen(Str);
if ( i >= v2 )
break;
Src = Str[i];
sscanf(&Src, "%d", &v7);
v6 += v7;
if ( v6 == 16 )
parell(Str, a2);}
return printf("Password Incorrect!\n");
}
int *__cdecl parell(char *Src, int a2){
int *result; // eax
int i; // [esp+10h] [ebp-8h]
int v4; // [esp+14h] [ebp-4h]
sscanf(Src, "%d", &v4);
result = (int *)dummy(v4, a2);
if ( result )
{
for ( i = 0; i <= 9; ++i ){
if ( !(v4 & 1) ){
printf("Password OK!\n");
exit(0);
}
result = &i;
}
}
return result;
}
signed int __cdecl dummy(int a1, int a2)
{
int v2; // ecx
int v5; // [esp+14h] [ebp-4h]
v5 = 0;
while ( *(_DWORD *)(4 * v5 + a2) ) // 1 == True
{
v2 = 4 * v5++; // 4 or 0
if ( !strncmp(*(const char **)(v2 + a2), "LOLO", 3u) )
return 1;
}
return 0;
}
它从main到check再到parallel(如果条件完全正确,然后是dummy,这将创建一个无限循环,除了:if//!strncmp(*(const char**)(v2+a2),“LOLO”,3u)==1,问题是我//main中的这个envp变量a2意味着什么
这是解的暗示,正如我所说,我被困在第二个条件(无限循环)上:
级别0x06:与5中的算法相同,但envp LOLO=1
最佳答案
const char**envp应该做什么?
正如@Vlad在评论中告诉您的,它envp
类似于argv
,但它不是程序参数,而是将进程的环境变量传递给它。这些是相同的键/值对,可以通过getenv()
函数访问或通过putenv()
函数设置。进程从其父进程接收它们,通常只需继承其父环境的副本。贝壳有一个操作这些界面的用户界面,例如,在bash
中,可以使用命令LOLO=1
将一个名为“洛洛”的环境变量设置为“1”。Windows外壳对同一件事有不同的语法。
如果您分析您所呈现的代码,您将看到envp
只是通过几个级别的函数传递(作为int
),直到最终在dummy()
中使用(仅限)。您将进一步注意到dummy()
没有使用它的其他参数——它所做的只是分析它的第二个参数(转换回指针)指向的数据。特别是,它看起来像是在扫描整个环境,寻找任何名称以“LOL”开头的环境变量——如果找到一个,则返回1,否则返回0。这就解释了您所询问的提示:不足以确定密码;除非将适当的环境变量设置为任何值,否则不接受密码。”“LOLO”将是这样一个变量的名称。
实际的密码检查是在check
和parell
函数中进行的。前者对密码字符串中的十进制数字执行预检查,将数字相加为16。如果这是满意的(即使这发生在密码结束之前),那么它将把整个密码交给函数parell
进行进一步的测试。这里是执行环境检查的位置,如果通过,则密码的前十进制数字将转换为一个数字,只要该数字是偶数,则接受密码。
假设反编译程序正确地完成了工作,那么只要设置了环境变量,就可以接受许多密码:
88
4444
23452
包括利用
check
和parell
执行的解析中的一些怪癖,例如0d79
2pwned!!
另外,在
main()
中输入的密码可能会受到缓冲区溢出的影响,因此您可以从完全不同的方向着手解决问题。关于c - const char ** envp应该做什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57009937/