小于1 kb的GUI应用程序

有空时,我问自己是否可以创建具有以下要求的应用程序:

  • 至少一些有用的应用程序功能(即不是虚拟的)
  • 窗口界面的存在
  • 大小小于1 Kb

通常,大小不超过1 Kb的应用程序标准是1k intro,这是一种演示。 通常,这是用汇编器编写的OpenGL初始化,然后向其提供着色器,着色器完成了主要工作(绘制了一些彩色的分形)。 另外,打包机(例如折皱机)也可以收割所有这些东西。
这些应用程序几乎被舔了一个字节,它们的开发需要数周甚至数月的时间。

这种方法太苛刻,我决定不超越WinAPI上通常的应用程序编程。

这时,在Steam上开始了夏季大减价,邀请大人用浏览器中的鼠标明智地摇晃外星人(是的,如Gabe所言,Valve再次制作游戏)。
这使我感到恼火,因此我决定尝试以最少的设置实现最简单的自动点击程序。

需容纳1 KB:

  • 接口创建和初始化
  • 具有事件处理程序的窗口函数
  • 主应用程序逻辑(基于GetAsyncKeyState和SendInput函数构建)

该应用程序将在MSVC中以纯C语言创建,无需汇编程序和SMS,然后使用Crinkler Packer压缩。 应该注意的是,crinkler压缩数据(尤其是稀有数据)的效率比代码压缩效率高(大约两倍)。 因此,我们将尝试将最大的功能转移到数据中。

从每个窗口元素的经典CreateWindow开始,我意识到我无法适应所需的大小。

我不得不寻找替代方案。 她成为函数CreateDialogIndirect,从填充的DLGTEMPLATE结构(由堆DLGITEMTEMPLATE组成)创建对话框

为了方便创建和填充结构,我开始了一些如下的宏:

#define NUMCHARS(p) (sizeof(p)/sizeof((p)[0])) #define DLGCTL(a) struct{DWORD style; DWORD exStyle; short x; short y; short cx; short cy; WORD id; WORD sysClass; WORD idClass; WCHAR wszTitle[NUMCHARS(a)]; WORD cbCreationData;} #define RADIO(x,y,cx,cy,id,title) {WS_VISIBLE|WS_CHILD|BS_RADIOBUTTON, 0, (x)/2, (y)/2,\n (cx)/2,(cy)/2, id, 0xFFFF, 0x0080, title, 0} 

现在,您可以声明结构并将其与Future窗口的元素一起填充:

 static struct { DWORD style; DWORD dwExtendedStyle; WORD ccontrols; short x; short y; short cx; short cy; WORD menu; WORD windowClass; DLGCTL(LBL_BTN_LEFT) button_left; DLGCTL(LBL_BTN_MIDDLE) button_middle; DLGCTL(LBL_BTN_RIGHT) button_right; } Dlg = { WS_VISIBLE|WS_POPUP|WS_BORDER, 0, TOTAL_CONTROLS, 50/2, 50/2, WND_CX/2, WND_CY/2, 0, 0, RADIO(10, 0, 80, 30, IDC_BTN_LEFT, LBL_BTN_LEFT), RADIO(100, 0, 80, 30, IDC_BTN_MIDDLE, LBL_BTN_MIDDLE), RADIO(190, 0, 68, 30, IDC_BTN_RIGHT, LBL_BTN_RIGHT), }; 

我们输入CreateDialogIndirect函数的结构,这是结果窗口:



由于我们的文件大小为1 kb,因此没有其他任何清单,因此也没有视觉样式。 就像青年时代一样,一切都是灰色和方形的。

但是我们仍然躲闪,从shell32.dll中提取清单并将基于它的上下文应用于我们的应用程序:

 static ACTCTX actCtx = {sizeof(ACTCTX), ACTCTX_FLAG_RESOURCE_NAME_VALID|ACTCTX_FLAG_SET_PROCESS_DEFAULT|ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, "shell32.dll", 0, 0, tmp, (LPCTSTR)124, 0, 0}; GetSystemDirectory(tmp,sizeof(tmp)); LoadLibrary("shell32.dll"); ActivateActCtx(CreateActCtx(&actCtx),(ULONG_PTR*)&tmp); 

已经很时髦了:



我们设法将window函数缩小为一个相当紧凑的函数:

 switch(msg) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_BTN_LEFT: case IDC_BTN_MIDDLE: case IDC_BTN_RIGHT: input[0].mi.dwFlags = wParam; input[1].mi.dwFlags = (wParam<<1); CheckRadioButton(hWnd,IDC_BTN_LEFT,IDC_BTN_MIDDLE,wParam); break; case IDC_BTN_HOLD: case IDC_BTN_TRIGGER: trigger_mode = (wParam==IDC_BTN_TRIGGER); CheckRadioButton(hWnd,IDC_BTN_HOLD,IDC_BTN_TRIGGER,wParam); break; case IDC_EDIT_PERIOD: period = GetDlgItemInt(hWnd,IDC_EDIT_PERIOD,(BOOL*)&tmp[0],0); break; case IDC_BTN_EXIT: exit(0); } break; } return DefWindowProc(hWnd,msg,wParam,lParam); 

然后我认为最好添加命令行参数处理,以便用户有机会从必要的设置开始。

例如:

input.exe /L /T /P:20 /K:9 - 20 , / Tab

将功能的一部分移到数据中,并得到类似以下内容的信息:

 static unsigned int arg_to_cmd[] = {IDC_BTN_HOLD, 0, 0, IDC_EDIT_KEY, IDC_BTN_LEFT, IDC_BTN_MIDDLE, 0, 0, IDC_EDIT_PERIOD, 0, IDC_BTN_RIGHT, 0, IDC_BTN_TRIGGER}; i = (char*)GetCommandLine(); while(*i) { if (*(i++)=='/')//looking for argument switch(*i) { case 'L': case 'M': case 'R': case 'H': case 'T': SendMessage(hWnd,WM_COMMAND,arg_to_cmd[*i-'H'],0);//send button command break; case 'P': case 'K': t = atoi(i+2); SetDlgItemInt(hWnd,arg_to_cmd[*i-'H'],t,0); if(*i=='P') period = t; else key = t; break; } } 

处理程序出来的很小。 自然,没有检查和防止错误输入的保护,只有必要的最低限度。

现在的主要功能(我将其放在单独的流中):

 while(1) { key_state = (GetAsyncKeyState(key)>>1); if (trigger_mode) { if ((key_state)&&(key_state!=prev_key_state)) active^= 1; prev_key_state = key_state; } else active = key_state; if (active) SendInput(2,(LPINPUT)&input,sizeof(INPUT)); Sleep(period); } 


我们按生成的obj文件crinkler'om-输出为973字节。

其中,数据占163字节(压缩率33.1%),代码占517字节(压缩率68.9%)。

可以缩小和增强(另外50个字节),但是目标已经实现。 甚至剩下51个备用字节。

在此过程中添加了初始要求:

  • 处理命令行参数
  • 显示具有视觉样式的窗口

在某些地方,代码看起来很歪。 这是因为我歪曲地写了它。 在某些地方,这可以节省空间。

当然,您可以想出更多的方法来减小应用程序的大小,但是并不是很大(我认为字节是50)。

结果:

现在,您可以自动模式召唤外星人,每秒造成巨大伤害。

可以创建具有实际使用的有用功能和窗口界面的超紧凑型应用程序。

新颖性:
零 我整理了一堆技术/发展。

权宜之计:
没用,好玩。

源代码
二元

接受批评,希望,建议,钦佩,愤慨。

Source: https://habr.com/ru/post/zh-CN416135/


All Articles