flower_tea
1、call与retn的花指令
call loc_140001224 //call到loc_140001224位置,并将栈顶设置为返回地址0x14000121F
pop rax //将栈顶元素(返回地址)弹到rax中
add rax, 0Ch //将rax加上0x0C
push rax //将rax入栈,即将当前rax的值作为返回地址
retn //读取栈顶地址(0x14000121F+0x0C)返回
2、除了IsDebuggerPresent API外,另一个反调试检测:
在x64下,调试标志位(BeingDebugged flag)在PEB表(Process Environment Block)偏移0x2的位置;通过获取gs寄存器找到peb表(gs:[0x60])的位置;readgsqword(0x62)得到调试标志位,读取该值如果该值为1,表示当前进程正在被调试;如果为0,则表示当前进程没有被调试。
3、之前提过,又hook的地方肯定存在virtualprotect,通过异或把virtualprotect函数名字改了也是逆天
FARPROC GetProcAddress(
HMODULE hModule,
LPCSTR lpProcName
);
参数
hModule:这是一个模块句柄,指向包含函数或变量的 DLL 模块。这个句柄通常由 LoadLibrary 或 GetModuleHandle 函数返回。
lpProcName:这是一个指向以空结尾的字符串,包含要检索的函数或变量的名称,或者包含函数的序号(由 MAKEINTRESOURCE 宏生成)。
返回值
成功时,返回值是名称为lpProName的函数或变量的地址。
失败时,返回值为 NULL。可以通过调用 GetLastError 函数获取更多的错误信息。
而对于ModuleName,可能是反编译的问题,不细究了,下图是题解的显示
所以GetProcAddress()通过在kernel32.dll用到的virtualprotect获得了virtualprotect函数的地址
所以函数返回virtualprotect函数的地址
4、对virtualprotect函数的认识
BOOL VirtualProtect(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);
参数
lpAddress:指向要更改保护属性的内存区域的起始地址。必须是系统分配的页面中的地址。
dwSize:要更改保护属性的内存区域的大小(以字节为单位)。
flNewProtect:新的保护属性。可以是以下值之一(或它们的组合):
PAGE_NOACCESS (0x01):禁止所有访问。
PAGE_READONLY (0x02):允许读取访问。
PAGE_READWRITE (0x04):允许读写访问。
PAGE_WRITECOPY (0x08):允许写入时复制访问。
PAGE_EXECUTE (0x10):允许执行访问。
PAGE_EXECUTE_READ (0x20):允许执行和读取访问。
PAGE_EXECUTE_READWRITE (0x40):允许执行、读取和写入访问。
PAGE_EXECUTE_WRITECOPY (0x80):允许执行和写入时复制访问。
PAGE_TARGETS_INVALID:指定目标区域内的所有代码地址都无效。
PAGE_TARGETS_NO_UPDATE:禁止更新目标区域内的代码地址。
lpflOldProtect:指向一个变量,该变量接收之前的保护属性。
返回值
如果函数成功,返回值为非零值。
如果函数失败,返回值为零。可以调用 GetLastError 函数获取扩展错误信息。
题中第三个参数便是64(0x40),允许执行、读取和写入访问。
5、依旧是call,retn花指令
rsp(Stack Pointer)寄存器包含了当前栈的顶部地址
与第一点相同,call后会将返回地址0x1400014BA压栈,而
sub qword ptr [rsp+0], 5Ah //则将栈顶地址减去了0x5A,即将返回地址变为了0x1400014BA-0x5A=0x140001460
mov rdx, 1 //rdx=1
test rdx, rdx //rdx进行&操作,rdx还是1
jz loc_140001489 //因为rdx为1所以不会跳转
retn
所以我们要在0x140001460位置重新反汇编,call loc_140001489与loc_140001489里的内容直接nop掉即可
6、call,pop,jmp花指令
call后将0x140001648存入栈顶,pop rax将栈顶传给rax,又jmp rax,相当于直接retn了
7、stack frame is too big
成因:分析栈帧时有异常出现
解决方案:找到明显不合常理的stack 双击进入栈帧界面,按U键盘删除对应的stack
有可能加壳
可能由花指令导致,手动或自动检查并去掉花指令
此题是因为去花导致分析异常,用解决方法1,双击进入stack界面
按U将异常出undefine
8、对于int64转为int32
delta[0] = 0xE1C49E7259578627ui64;
delta[1] = 0x8C3DA26BBC24167Fui64;
unsigned int delta[4]={0x59578627,0xE1C49E72,0xBC24167F,0x8C3DA26B}
9、魔改tea,可以将delta的值魔改成数组,每次对应的delta不同
//encode:
for (int i = 0; i <15 ; i+=4) {
for (int j = 0; j <= 32; ++j) {
sum += delta[flag[i]%4];
flag[i] += (sum >> 3) ^ (4 * ke[j%4]) ^ sum ^ flag[i+3];
sum += delta[flag[i+1]%4];
flag[i+1] += (16 * sum) ^ (ke[(j+1)%4] >> 1) ^ sum ^ flag[i];
sum += delta[flag[i+2]%4];
flag[i+2] += (sum >> 2) ^ (8 * ke[(j+2)%4]) ^ sum ^ flag[i+1];
sum +=delta[flag[i+3]%4];
flag[i+3] += (2 * sum) ^ (ke[(j+3)%4] >> 2) ^ sum ^ flag[i+2]
}
}
//偷的decode,我写的感觉和以这个一样啊,但是就是结果不对
//decode:
for (i = 0; i < len; i += 4) {
uint32_t* c[4] = { &flag[(len - (i + 3)) % len],&flag[(len - (i + 2))
% len],&flag[(len - (i + 1)) % len],&flag[(len - i) % len] };
for (j = 32; j >= 0; j--) {
*c[3] -= ((e ^ *c[2]) ^ (key[(j + 3) % 4] >> 2)) ^ (e << 1);
e -= delta[*c[3] % 4];
*c[2] -= ((e ^ *c[1]) ^ (key[(j + 2) % 4] << 3)) ^ (e >> 2);
e -= delta[*c[2] % 4];
*c[1] -= ((e ^ *c[0]) ^ (key[(j + 1) % 4] >> 1)) ^ (e << 4);
e -= delta[*c[1] % 4];
*c[0] -= ((e ^ *c[3]) ^ (key[j % 4] << 2)) ^ (e >> 3);
e -= delta[*c[0] % 4];
}
elec_go
Electron(原名为Atom Shell[6])是GitHub开发的一个开源框架。[7]它通过使用Node.js(作为后端)和Chromium的渲染引擎(作为前端)完成跨平台的桌面GUI应用程序的开发。Electron现已被多个开源Web应用程序用于前端与后端的开发,著名项目包括GitHub的Atom和微软的Visual Studio Code。[8][9]
一个基础的Electron包含三个文件:package.json(元数据)、main.js(代码)和index.html(图形用户界面)。框架由Electron可执行文件(Windows中为electron.exe、macOS中为electron.app、Linux中为electron)提供。开发者可以自行添加标志、自定义图标、重命名或编辑Electron可执行文件。
Debug
1、die没查出壳,但是直接拖到ida中发现,函数非常少,很可能是进行了某些操作,对其加密
既然die不行,那就多试试别的,就此,我顺便把其他几个更新一下