载入IDA
__int64 main_0() { int v0; // edx __int64 v1; // ST04_8 char v3; // [esp+0h] [ebp-160h] int v4; // [esp+D0h] [ebp-90h] int j; // [esp+DCh] [ebp-84h] int i; // [esp+E8h] [ebp-78h] char Str[104]; // [esp+F4h] [ebp-6Ch] srand(0xCu); j_memset(&unk_423D80, 0, 0x9C40u); for ( i = 1; i <= 20; ++i ) { for ( j = 1; j <= i; ++j ) dword_41A138[100 * i + j] = rand() % 100000; } ((void (__cdecl *)(const char *, char))sub_41134D)("input your key with your operation can get the maximum:", v3); sub_411249("%s", (unsigned int)Str); if ( j_strlen(Str) == 19 ) { sub_41114F(Str); v4 = 0; j = 1; i = 1; dword_423D78 += dword_41A138[101]; while ( v4 < 19 ) { if ( Str[v4] == 76 ) { dword_423D78 += dword_41A138[100 * ++i + j]; } else { if ( Str[v4] != 82 ) { ((void (__cdecl *)(const char *, char))sub_41134D)("error\n", v3); system("pause"); goto LABEL_18; } dword_423D78 += dword_41A138[100 * ++i + ++j]; } ++v4; } sub_41134D("your operation can get %d points\n", dword_423D78); system("pause"); } else { ((void (__cdecl *)(const char *, char))sub_41134D)("error\n", v3); system("pause"); } LABEL_18: HIDWORD(v1) = v0; LODWORD(v1) = 0; return v1; }首先生成一个数组存在。这个数组由伪随机数生成。srand(0xCu)随机数种子一定,那么rand出来的数也是一定的。
然后往下看,下面是自己加入了注释。
总得来看就是先将从arr[101] 相加,往下的循环为:
第一次循环:经过用户按"L"或"R"来控制加arr[201]还是arr[202]
第二次循环:(情况1)第一次选择了arr[201]:经过用户按"L"或"R"来控制加arr[301]还是arr[302] (情况2)第二次选择了arr[202]:经过用户按"L"或"R"来控制加arr[302]还是arr[303]
跟两次循环帮组理解,这样子就很清楚了。整个题可以理解成站在山顶往下走,每一行走到的数字累加,每次只能走一格(左或右),走到最后一行。然后最后的数要最大。与题目Mountain climbing呼应
那首先要先找到这座山,看ida反编译后是dword_41A138存在0041A138,我们用OD载入后运后,跟过去看看。
dword是4字节的,而且第一个数是存在在[101]位置的。所以首位置存在41A2CC位置。往下的都是往后400节。
还是要注意小端存储问题。所以可以得到arr[101] = 4D(16进制) =77 , arr[201] = 15FC(16进制) = 5628(10进制) , arr[202] = 1858(16进制) = 6232(10进制)
有耐心的话可以一行行扣出来 ,没有的话,直接还原c代码生成"一座山"。
代码如下:
得到完整的,与OD获取的值是一致。
接下来就是找到最大解的路线。直接遍历所有路线,然后比较最大数。
首先生成所有路径
#!usr/bin/env python #!coding=utf-8 __author__ = 'zhengjim' import itertools words = "LR" r = itertools.product(words,repeat=19) f = open("all_roads.txt",'a') for i in r: f.write("".join(i)+"\n") f.close()