一 加密函数
1. base64加密函数
(1)buuctf 刮开有奖1(未转换)
_BYTE *__cdecl sub_401000(int a1, int a2)
{
int v2; // eax
int v3; // esi
size_t v4; // ebx
_BYTE *v5; // eax
_BYTE *v6; // edi
int v7; // eax
_BYTE *v8; // ebx
int v9; // edi
int v10; // edx
int v11; // edi
int v12; // eax
int i; // esi
_BYTE *result; // eax
_BYTE *v15; // [esp+Ch] [ebp-10h]
_BYTE *v16; // [esp+10h] [ebp-Ch]
int v17; // [esp+14h] [ebp-8h]
int v18; // [esp+18h] [ebp-4h]
v2 = a2 / 3;
v3 = 0;
if ( a2 % 3 > 0 )
++v2;
v4 = 4 * v2 + 1;
v5 = malloc(v4);
v6 = v5;
v15 = v5;
if ( !v5 )
exit(0);
memset(v5, 0, v4);
v7 = a2;
v8 = v6;
v16 = v6;
if ( a2 > 0 )
{
while ( 1 )
{
v9 = 0;
v10 = 0;
v18 = 0;
do
{
if ( v3 >= v7 )
break;
++v10;
v9 = *(unsigned __int8 *)(v3 + a1) | (v9 << 8);
++v3;
}
while ( v10 < 3 );
v11 = v9 << (8 * (3 - v10));
v12 = 0;
v17 = v3;
for ( i = 18; i > -6; i -= 6 )
{
if ( v10 >= v12 )
{
*((_BYTE *)&v18 + v12) = (v11 >> i) & 0x3F;
v8 = v16;
}
else
{
*((_BYTE *)&v18 + v12) = 64;
}
*v8++ = byte_407830[*((char *)&v18 + v12++)];
v16 = v8;
}
v3 = v17;
if ( v17 >= a2 )
break;
v7 = a2;
}
v6 = v15;
}
result = v6;
*v8 = 0;
return result;
}
二 功能函数
1. 排序函数
(1)buuctf 刮开有奖1(未转换)
v7[0] = 90;
v7[1] = 74;
v8 = 83;
v9 = 69;
v10 = 67;
v11 = 97;
v12 = 78;
v13 = 72;
v14 = 51;
v15 = 110;
v16 = 103;
int __cdecl sub_4010F0(int a1, int a2, int a3)
{
int result; // eax
int i; // esi
int v5; // ecx
int v6; // edx
result = a3;
for ( i = a2; i <= a3; a2 = i )
{
v5 = 4 * i;
v6 = *(_DWORD *)(4 * i + a1);
if ( a2 < result && i < result )
{
do
{
if ( v6 > *(_DWORD *)(a1 + 4 * result) )
{
if ( i >= result )
break;
++i;
*(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result);
if ( i >= result )
break;
while ( *(_DWORD *)(a1 + 4 * i) <= v6 )
{
if ( ++i >= result )
goto LABEL_13;
}
if ( i >= result )
break;
v5 = 4 * i;
*(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1);
}
--result;
}
while ( i < result );
}
LABEL_13:
*(_DWORD *)(a1 + 4 * result) = v6;
sub_4010F0(a1, a2, i - 1);
result = a3;
++i;
}
return result;
}
2.数学函数
ctfshow - 数学不及格(线性求解斐波拉契数列)返回值为斐波那契数列第n项
__int64 __fastcall f(int a1)
{
int i; // [rsp+1Ch] [rbp-14h]
__int64 v3; // [rsp+20h] [rbp-10h]
_QWORD *ptr; // [rsp+28h] [rbp-8h]
if ( a1 <= 1 || a1 > 200 )
return 0LL;
ptr = malloc(8LL * a1);
*ptr = 1LL;
ptr[1] = 1LL;
v3 = 0LL;
for ( i = 2; i < a1; ++i )
{
ptr[i] = ptr[i - 1] + ptr[i - 2];
v3 = ptr[i];
}
free(ptr);
return v3;
}
三 各种库函数
C语言
stdlib.h 库 strtol()
描述
C 库函数 *long int strtol(const char *str, char *endptr, int base) 把参数 str 所指向的字符串根据给定的 base 转换为一个长整数(类型为 long int 型),base 必须介于 2 和 36(包含)之间,或者是特殊值 0。
声明
下面是 strtol() 函数的声明。
long int strtol(const char *str, char **endptr, int base)
参数
- str – 要转换为长整数的字符串。
- endptr – 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符。
- base – 基数,必须介于 2 和 36(包含)之间,或者是特殊值 0。转换数字的进制数。
返回值
该函数返回转换后的长整数,如果没有执行有效的转换,则返回一个零值。
实例
下面的实例演示了 strtol() 函数的用法。
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[30] = "2030300 This is test";
char *ptr;
long ret;
ret = strtol(str, &ptr, 10);
printf("数字(无符号长整数)是 %ld\n", ret);
printf("字符串部分是 |%s|", ptr);
return(0);
}
让我们编译并运行上面的程序,这将产生以下结果:
数字(无符号长整数)是 2030300
字符串部分是 | This is test|
stdlib.h 库 atoi()
atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数,应用在计算机程序和办公软件中。int atoi(const char *nptr) 函数会扫描参数 nptr字符串,会跳过前面的空白字符(例如空格,tab缩进)等。如果 nptr不能转换成 int 或者 nptr为空字符串,那么将返回 0 。 特别注意,该函数要求被转换的字符串是按十进制数理解的。atoi输入的字符串对应数字存在大小限制(与int类型大小有关),若其过大可能报错-1。
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int n;
char *str = "12345.67";
n = atoi(str);
printf("n=%d\n",n);
return 0;
}
输出为 n = 12345
#include <stdlib.h>
#include <stdio.h>
int main()
{
char a[] = "-100";
char b[] = "123";
int c;
c = atoi(a) + atoi(b);
printf("c=%d\n", c);
return 0;
}
输出为 c = 23
四 PE文件详解
五 加壳与脱壳的原理和实现
六 Windows核心编程
Hello,world
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
MessageBox(NULL, TEXT("hello,world"), TEXT("title"), MB_OK | MB_ICONWARNING | MB_DEFBUTTON1);
return 0;
}
字符类型
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
const TCHAR* szContant = TEXT("hello,world");
static TCHAR szCaption[] = TEXT("title");
MessageBox(NULL, szContant, szCaption, MB_OK | MB_ICONWARNING | MB_DEFBUTTON1);
return 0;
}
MessageBox(NULL, TEXT("hello,world"), TEXT("title"), MB_OK | MB_ICONWARNING | MB_DEFBUTTON1);
return 0;
}
窗口定义
Windows 的窗口总是基于窗口类来创建的,窗口类同时确定了处理窗口消息的窗口过程(回调函数)。
在创建应用程序窗口之前,必须调用 RegisterClass 函数来注册窗口类。该函数只需要一个参数,即指向 WNDCLASS 窗口类的指针。因为 WNDCLASS 类包含了窗口所拥有的基本属性。
结构原型:
1. typedef struct tagWNDCLASSW {
2. UINT style;
3. WNDPROC lpfnWndProc;
4. int cbClsExtra;
5. int cbWndExtra;
6. HINSTANCE hInstance;
7. HICON hIcon;
8. HCURSOR hCursor;
9. HBRUSH hbrBackground;
10. LPCWSTR lpszMenuName;
11. LPCWSTR lpszClassName;
12. } WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
成员解析:
成员 | 含义 |
style | 指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来 |
lpfnWndProc | 指定窗口过程(必须是回调函数) |
cbClsExtra | 预留的额外空间,一般为 0 |
cbWndExtra | 预留的额外空间,一般为 0 |
hInstance | 应用程序的实例句柄 |
hIcon | 为所有基于该窗口类的窗口设定一个图标 |
hCursor | 为所有基于该窗口类的窗口设定一个鼠标指针 |
hbrBackground | 指定窗口背景色 |
lpszMenuName | 指定窗口菜单 |
lpszClassName | 指定窗口类名 |
style 类风格解析
类风格 | 含义 |
CS_VREDRAW | 移动或者调整窗口的高度(垂直方向)时,重绘整个窗口 |
CS_HREDRAW | 移动或者调整窗口的宽度(水平方向)时,重绘整个窗口 |
CS_DBLCLKS | 当用户光标在窗口内双击时,允许发送双击消息给窗口过程 |
CS_OWNDC | 给予每个窗口实例分配一个唯一的 DC(注意,尽管这样是很方便,但它必须慎重使用,因为每个 DC 大约要占 800 个字节的内存) |
CS_CLASSDC | 该窗口类的所有窗口实例都共享一个窗口类 DC |
CS_PARENTDC | 1. 将子窗口的裁剪区域设置到父窗口的 DC 中去,这样子窗口便可以在父窗口上绘制自身。(注意,这是子窗口从系统缓存中获取 DC,而不是使用父窗口的 DC。) 2. 指定该风格可以提高系统性能 |
CS_NOCLOSE | 禁止系统菜单的关闭选项 |
CS_SAVEBITS | 1. 以位图形式保存被该窗口遮挡的屏幕部分,当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息 2. 该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失 3. 设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存 |
CS_BYTEALIGNCLIENT | 在字节边界上(在 x 方向上)定位窗口的用户区域的位置 |
CS_BYTEALIGNWINDOW | 在字节边界上(在 x 方向上)定位窗口的位置 |
CS_GLOBALCLASS | 1. 当调用 CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的 hInstance 参数和注册窗口类时传递给 RegisterClass 的 hInstance 参数不同 2. 如果不指定该风格,则这两个 hInstance 必须相同 |
*call的使用
__cdecl
__cdecl 是 C Declaration 的缩写,表示 C 语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。
__stdcall
__stdcall 是 Standard Call 的缩写,是 C++ 的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,最后一个入栈的是 this 指针。这些堆栈中的参数由被调用的函数在返回后清除,使用的指令是 retnX,X 表示参数占用的字节数,CPU 在 ret 之后自动弹出 X 个字节的堆栈空间,称为自动清栈。函数在编译的时候就必须确定参数个数,并且调用者必须严格的控制参数的生成,不能多,不能少,否则返回后会出错。
__pascal
__pascal 是 Pascal 语言(Delphi)的函数调用方式,也可以在 C/C++ 中使用,参数压栈顺序与前两者相反。返回时的清栈方式与 __stdcall 相同。
__fastcall
__fastcall 是编译器指定的快速调用方式。由于大多数的函数参数个数很少,使用堆栈传递比较费时。因此 __fastcall 通常规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递。不同编译器编译的程序规定的寄存器不同,返回方式和 __stdcall 相当。
__thiscall
__thiscall 是为了解决类成员调用中 this 指针传递而规定的。__thiscall 要求把 this 指针放在特定寄存器中,该寄存器由编译器决定。VC 使用 ecx,Borland 的 C++ 编译器使用 eax。返回方式和 __stdcall 相当。
__fastcall 和 __thiscall 涉及的寄存器由编译器决定,因此不能用作跨编译器的接口。所以 Windows 上的 COM 对象接口都定义为 __stdcall 调用方式。
C 语言中不加说明默认函数为 __cdecl 方式(C中也只能用这种方式),C++ 也一样,但是默认的调用方式可以在 IDE 环境中设置。
例子:test1(par1, par2, par3);
*大写标识符的含义
在 Winodows 的定义中包含着许多大写标识符,这些标识符有很多都是以两个或三个字母作为前缀,且其后紧跟一个下划线:
CS_HREDRAW DT_VCENTER SND_FILENAME
CS_VREDRAW IDC_ARROW WM_CREATE
CW_USEDEFAULT IDI_APPLICATION WM_DESTROY
DT_CENTER MB_ICONERROR WM_PAINT
DT_SINGLELINE SND_ASYNC WS_OVERLAPPEDWINDOW
这些标识符其实都是宏定义,前缀标明该常量所属的一般类别,含义如下表:
前缀 | 含义 |
CS | 类风格选项(ClassStyle) |
CW | 创建窗口选项(CreateWindow) |
DT | 文本绘制选项(DrawText) |
IDI | 图标的 ID 号(IDIcon) |
IDC | 光标的 ID 号(IDCursor) |
MB | 消息框选项(MessageBox) |
SND | 声音选项(Sound) |
WM | 窗口消息(WindowsMessage) |
WS | 窗口风格(WindowStyles) |