-
mui如何实现扫码功能
2019-11-28 14:52:04小编改写了一个扫码二维码功能,这个虽然网络上的案例有很多,基本上都是扫一下后就弹出提示框,提示框里就是二维码的链接,小编改成扫描二维码后对应相对的网站,包含了内部浏览器,为什么要弄个内部浏览器呢?...小编改写了一个扫码二维码功能,这个虽然网络上的案例有很多,基本上都是扫一下后就弹出提示框,提示框里就是二维码的链接,小编改成扫描二维码后对应相对的网站,包含了内部浏览器,为什么要弄个内部浏览器呢?因为mui跳转网站内容的话那APP就会自动关闭掉,所以需要弄个内部浏览器用于浏览外链网站的。
如何实现呢?添加三个文件(点击进入扫码 -> 扫码 ->扫码后的结果)
- index.html:是首页,需要写个点击事件进入扫码页(小编就不写这个页面了)
- Ewm.html:是扫码页
- target.html:是扫码后的结果页面
Ewm页面
<!doctype html> <html> <head> <meta charset="UTF-8"> <title></title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link href="../css/mui.min.css" rel="stylesheet" /> <script src="../js/mui.min.js"></script> <style type="text/css"> #bcid{ width: 100%; height: 86.5%; position: absolute; background: #000000; top:45px; } html, body ,div{ height:100%; width: 100%; } .fbt{ color: #0E76E1; width: 50%; background-color: #ffffff; float: left; line-height: 44px; text-align: center; } #turnTheLight{ font-size:15px; line-height: 25px; color:#8F8F94; } </style> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title" style="color: #0E76E1;">物品二维码扫描</h1> <span class="mui-icon mui-spin mui-pull-right" id="turnTheLight">闪光灯</span> </header> <!--盛放扫描控件的div--> <div id="bcid"></div> <div class="mui-bar mui-bar-footer" style="padding: 0px;"> <div class="fbt" onclick="scanPicture();">从相册选择二维码</div> <div class="fbt mui-action-back">取 消</div> </div> <script type="text/javascript"> scan = null;//扫描对象 mui.plusReady(function () { mui.init(); startRecognize(); }); function startRecognize(){ try{ var filter; //自定义的扫描控件样式 var styles = {frameColor: "#29E52C",scanbarColor: "#29E52C",background: ""} //扫描控件构造 scan = new plus.barcode.Barcode('bcid',filter,styles); scan.onmarked = onmarked; scan.onerror = onerror; scan.start(); //打开关闭闪光灯处理 var flag = false; document.getElementById("turnTheLight").addEventListener('tap',function(){ if(flag == false){ scan.setFlash(true); flag = true; }else{ scan.setFlash(false); flag = false; } }); }catch(e){ alert("出现错误啦:\n"+e); } }; function onerror(e){ alert(e); }; function onmarked( type, result ) { var text = ''; switch(type){ case plus.barcode.QR: text = 'QR: '; break; case plus.barcode.EAN13: text = 'EAN13: '; break; case plus.barcode.EAN8: text = 'EAN8: '; break; } //弹出链接 // alert( text + result ); mui.openWindow({ url: "target.html?url=" + result, id: "target" }); }; // 从相册中选择二维码图片 function scanPicture() { plus.gallery.pick(function(path){ plus.barcode.scan(path,onmarked,function(error){ plus.nativeUI.alert( "无法识别此图片" ); }); },function(err){ plus.nativeUI.alert("Failed: "+err.message); }); } </script> </body> </html>
target.html
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>目标页面</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <link href="../css/mui.min.css" rel="stylesheet" /> </head> <body> <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left" id="go_back"></a> <h1 class="mui-title mui-action-back" id="close_page">扫后详情</h1> </header> <script src="../js/mui.min.js"></script> <script type="text/javascript"> var str=window.location.search; var myid=str.substring(str.indexOf('=')+1) mui.init(); mui.plusReady(function() { var self = plus.webview.currentWebview(); var baiduWV = plus.webview.create(myid, "baidu", { //这里定义页面高度 top: "44px", bottom: 0 }); self.append(baiduWV); }); </script> </body> </html>
效果:
扫码页面(有闪光灯功能)
扫码后
别忘记引入mui自带的css和js喔!!!这篇文章希望对您有帮助
-
【Cocos2dx】利用导演类、场景类完成重新开始游戏、暂停游戏、关闭游戏功能
2015-10-31 11:12:38下面用一个小例子说明如何利用导演类、场景类完成重新开始游戏、暂停游戏、关闭游戏功能, 这个被改写的HelloWorld场景,一开始就声明一个在屏幕中央开始5s内上升100px的按钮精灵, 可以看到,点击左上角的...重新开始游戏、暂停游戏、关闭游戏是绝对是游戏的基础,虽然代码不多,不过这要利用到Cocos2dx导演类、场景类完成,事先如果不对其进行了解,绝对是很难做出来。
下面用一个小例子说明如何利用导演类、场景类完成重新开始游戏、暂停游戏、关闭游戏功能,
这个被改写的HelloWorld场景,一开始就声明一个在屏幕中央开始5s内上升100px的按钮精灵,
可以看到,点击左上角的Refresh!按钮,这个场景的所有动作会重新开始,也就是,将HelloWorld场景销毁,重新执行HelloWorld场景的init()函数,相当于“重新开始游戏”。
点击右上角的Pause!按钮会保存当前HelloWorld场景的所有操作,来到一个新的Pause场景,点击其中的Back!按钮,会重新返回HelloWorld场景,按钮精灵会继续执行在屏幕中央开始5s内上升100px的动作,而不是重新开始,相当于"暂停游戏"。
"关闭游戏"在官方的Helloworld已经有,不过涉及这里的相关的知识,也在这里说说。
工程的文件结构如下:
“暂停游戏”必须新建一个带“返回”按钮场景,不新建这个暂停场景,是做不出来,虽然新建场景是一件复杂的事情,但你不这样做,是搞不出来的。
关于场景的概念在《【Cocos2dx】新建场景、场景的切换、设置启动场景与菜单的新建》(点击打开链接)已经讲过了,但这里着重对场景的scene函数的重写,这个scene函数相当于场景新建时候执行的构造函数。
先看改写了的HelloWorldScene:
HelloWorldScene.h,一些声明,没什么好说,只是删除一些官方无用的预编译声明、注释:
HelloWorldScene.cpp,看起来代码很长很长,然而在init()声明N个按钮起始是一大堆重复的,详情可以看《【Cocos2dx】使用CCControlButton创建按钮、按钮点击事件,点击事件中的组件获取,setPosition的坐标问题 》(点击打开链接),关键是各个函数的回调函数,核心是你要通过CCDirector::sharedDirector()召唤出导演,才能操作场景:#include "cocos2d.h" #include "cocos-ext.h" //使用按钮事件,必须要需要的头文件 USING_NS_CC_EXT;//使用按钮事件,必须要需要的命名空间 class HelloWorld:public cocos2d::CCLayer { public: virtual bool init();//场景初始化的函数 //场景声明函数 static cocos2d::CCScene* scene(); CREATE_FUNC(HelloWorld); void pause(CCObject* pSender,CCControlEvent event);//暂停 void restart(CCObject* pSender,CCControlEvent event);//重新开始 void close(CCObject* pSender,CCControlEvent event);//关闭 };
#include "HelloWorldScene.h" #include "PauseScene.h" USING_NS_CC; CCScene* HelloWorld::scene() { CCScene *scene = CCScene::create();//创建HelloWorld场景 HelloWorld *layer = HelloWorld::create();//创建HelloWorld层 scene->addChild(layer);//将HelloWorld层放在HelloWorld场景,所有元素只能放在层上,而不能放在场景上,场景仅能放层,相当于JavaSwing中在frame中添加panel才能继续搞 return scene; } bool HelloWorld::init() { //获取屏幕的尺寸、位置信息等 CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize(); //声明按钮部分 /*右上角按钮*/ CCScale9Sprite *btn_noraml1 = CCScale9Sprite::create("CloseNormal.png");//声明CloseNormal图片,用于按钮没被按下时的背景图片 CCLabelTTF *label1 = CCLabelTTF::create("Pause!","arial",36);//声明一个文字Pause!第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小 CCControlButton *controlButton1 = CCControlButton::create(label1,btn_noraml1); controlButton1->setAnchorPoint(ccp(1,1)); controlButton1->setPosition(ccp(visibleSize.width,visibleSize.height)); controlButton1->addTargetWithActionForControlEvents(this, cccontrol_selector(HelloWorld::pause), CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的HelloWorld::pause(){}中所有代码。 this->addChild(controlButton1);//将此按钮添加到场景,默认不自动添加 /*左上角按钮*/ CCScale9Sprite *btn_noraml2 = CCScale9Sprite::create("CloseNormal.png");//声明CloseNormal图片,用于按钮没被按下时的背景图片 CCLabelTTF *label2 = CCLabelTTF::create("Refresh!","arial",36);//声明一个文字Refresh!第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小 CCControlButton *controlButton2 = CCControlButton::create(label2,btn_noraml2); controlButton2->setAnchorPoint(ccp(0,1)); controlButton2->setPosition(ccp(0,visibleSize.height)); controlButton2->addTargetWithActionForControlEvents(this, cccontrol_selector(HelloWorld::restart), CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的HelloWorld::restart(){}中所有代码。 this->addChild(controlButton2);//将此按钮添加到场景,默认不自动添加 /*右下角按钮*/ CCScale9Sprite *btn_noraml3 = CCScale9Sprite::create("CloseNormal.png");//声明CloseNormal图片,用于按钮没被按下时的背景图片 CCLabelTTF *label3 = CCLabelTTF::create("Close!","arial",36);//声明一个文字Close!第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小 CCControlButton *controlButton3 = CCControlButton::create(label3,btn_noraml3); controlButton3->setAnchorPoint(ccp(1,0)); controlButton3->setPosition(ccp(visibleSize.width,0)); controlButton3->addTargetWithActionForControlEvents(this, cccontrol_selector(HelloWorld::close), CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的HelloWorld::close(){}中所有代码。 this->addChild(controlButton3);//将此按钮添加到场景,默认不自动添加 /*声明一个做动作的按钮精灵,以显示出效果*/ CCSprite *sprite=CCSprite::create("CloseSelected.png"); sprite->setPosition(ccp(visibleSize.width/2,visibleSize.height/2)); this->addChild(sprite); CCFiniteTimeAction* action2=CCMoveBy::create(5.0f,ccp(0,100));//在5秒内提升100px sprite->runAction(action2); return true; } void HelloWorld::pause(CCObject* pSender,CCControlEvent event) { //将游戏界面暂停,压入场景堆栈。并切换到GamePause界面 CCDirector::sharedDirector()->pushScene(PauseScene::scene()); } void HelloWorld::restart(CCObject* pSender,CCControlEvent event) { //将游戏界面重新开始,replaceScene意思是用一个新场景替换旧场景,旧场景被替换之后,马上被销毁 CCDirector::sharedDirector()->replaceScene(HelloWorld::scene()); } void HelloWorld::close(CCObject* pSender,CCControlEvent event) { //结束当前游戏 CCDirector::sharedDirector()->end(); exit(0); }
之后是暂停场景类PauseScene,PauseScene.h同样是一些声明:
#include "cocos2d.h" #include "cocos-ext.h" //使用按钮事件,必须要需要的头文件 USING_NS_CC_EXT;//使用按钮事件,必须要需要的命名空间 using namespace cocos2d; class PauseScene:public CCLayer{ public: static CCScene* scene(); virtual bool init(); CREATE_FUNC(PauseScene); void back(CCObject* pSender,CCControlEvent event);//返回场景 };
PauseScene.cpp则同样是放一个按钮,按钮的回调函数,同样是召唤出Cocos2dx的导演。暂停功能是这样的:Cocos2dx自身就自带一个场景栈,在初始化的时候,在main.cpp指定的开始场景就会自动进入场景栈,具体见《【Cocos2dx】Windows平台下Cocos2dx 2.x的下载、安装、配置,打造自己的Helloworld》(点击打开链接),暂停的话,CCDirector::sharedDirector()召唤出来的导演,有令让某一场景进入场景栈的方法pushScene,Cocos2dx只会演出当前在场景栈最上方的场景,下方的所有场景的行为、元素位置,通通会被存档、暂停,待其回到场景栈最顶部才会继续运行。
导演同样有让当前在场景栈最上方的场景出栈的方法。场景被出栈是马上被销毁,再也找不到了。
如果场景栈为空,则会自动关闭游戏,不过建议还是用导演的end()与exit(0)方法来结束游戏,这也是Cocos2dx官方的Helloworld使用的方法。
#include "PauseScene.h" USING_NS_CC; CCScene* PauseScene::scene() { CCScene *scene=CCScene::create(); PauseScene* pauseScene=PauseScene::create(); scene->addChild(pauseScene); return scene; } bool PauseScene::init() { //获取屏幕的尺寸、位置信息等 CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize(); //声明按钮部分 cocos2d::extension::CCScale9Sprite *btn_noraml = cocos2d::extension::CCScale9Sprite::create("CloseNormal.png");//声明CloseNormal图片,用于按钮没被按下时的背景图片 CCLabelTTF *label1 = CCLabelTTF::create("back!","arial",36);//声明一个文字Click me!第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小 CCControlButton *controlButton = CCControlButton::create(label1,btn_noraml); controlButton->setPosition(ccp(visibleSize.width/2,visibleSize.height/2));//按钮的中心点位于屏幕的中央 controlButton->addTargetWithActionForControlEvents(this, cccontrol_selector(PauseScene::back), CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的PauseScene::back(){}中所有代码。 this->addChild(controlButton);//将此按钮添加到场景,默认不自动添加 return true; } void PauseScene::back(CCObject* pSender,CCControlEvent event) { //本场景出栈 CCDirector::sharedDirector()->popScene(); }
-
在Ring3上实现文件碎甲(解锁)功能
2016-03-08 09:29:37在Ring3上实现文件碎甲(解锁)...现在我们会使用Unlocker之类的小工具去解锁,但在编写程序的可能会需要把这些功能包含在自己的代码中,本文就是自己写代码实现”如何关闭已经被加载的DLL或是正在使用的文件”功能,使在Ring3上实现文件碎甲(解锁)功能
一.概述:
如果一个病毒文件被植入正在运行的进程中,我们想要清除它时系统总会提供无法删除;有时编辑文件的进程被意外中止而文件句柄没有正确释放,导致此文件无法进行改写操作。现在我们会使用Unlocker之类的小工具去解锁,但在编写程序的可能会需要把这些功能包含在自己的代码中,本文就是自己写代码实现”如何关闭已经被加载的DLL或是正在使用的文件”功能,使用文章中的方法能很方便的完成文件解锁功能。
按最初的想法准备在ring0中完成这些功能,但在查找资料的过程中发现既然我们能在ring3中做,为什么不让这些方法更通用一些呢。其实功能实现并不难,主要是前期从哪里入手比较麻烦。
我们知道无论是动态库或是文件在加载到进程中时,总会有一个指向它的指针,如果让进程释放这段指针,那么这些文件就不会被系统锁定。下面将是我们的需要实现文件解锁功能而分解出的步骤
1. 枚举当前系统所有进程;
2. 查找进程中打开的文件句柄和加载的动态库句柄;
3. 通知进程关闭这些句柄。
二.详细设计
2.1查找进程加模的动态库模块
Let’s go,我们来分步完成它吧。对于枚举当前系统所有进程,在这里就不给出代码了,相信实现的方法很多。下面的代码段完成查找指定进程加载动库信息的功能(在这里使用了Jeffrey在《Windows核心编程》一书中提供的CToolhelp类,用它可以完成进程加载信息的分析功能,感谢Jeffrey,我一直在使用它)
// 自定义结构,保存打开句柄的的信息
typedef struct _UNFILE_INFO {
int nFileType;
DWORD dwHandle;
char *strFileName;
} UNFILE_INFO, *PUNFILE_INFO;
//
// 通过PID号取得PID打开的文件句柄信息
//
void
GetModules(DWORD dwProcessID, CList<PUNFILE_INFO, PUNFILE_INFO> &plsUnFileInfo)
{
CToolhelp::EnableDebugPrivilege(TRUE);
CToolhelp th(TH32CS_SNAPALL, dwProcessID);
// 显示进程的详细资料
MODULEENTRY32 me = { sizeof(me) };
BOOL fOk = th.ModuleFirst(&me);
for (; fOk; fOk = th.ModuleNext(&me))
{
PVOID pvPreferredBaseAddr = NULL;
pvPreferredBaseAddr =GetModulePreferredBaseAddr(dwProcessID, me.modBaseAddr);
// 取得进程模块信息
PUNFILE_INFO pUnFileInfo = new UNFILE_INFO;
// 模块地址
pUnFileInfo->dwHandle = (DWORD)me.modBaseAddr;
// 模块类型
pUnFileInfo->nFileType = UNTYPE_DLL;
// 模块名称
pUnFileInfo->strFileName = new char[strlen(me.szExePath)+1];
memset( pUnFileInfo->strFileName, 0, strlen(me.szExePath)+1);
strcpy( pUnFileInfo->strFileName, me.szExePath);
// 保存打开的模块信息
plsUnFileInfo.AddTail( pUnFileInfo);
}
}
上面功能完成了枚举进程加载的模块功能,我们把得到的枚举信息加入了链表中,以备后面使用。
2.2枚举进程打开的文件信息
下面将分段说明如何枚举指定进程打开的文件句柄。在这里我们需要使用两个DDK中提供的函数:
NTSTATUS
ZwQuerySystemInformation(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
NTSTATUS
ZwQueryInformationFile(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass
);
ZwQuerySystemInformation是个未公开函数,通过它的SYSTEM_INFORMATION_CLASS结构,我们能完成许多进程和线程的操作,下面是它的部分内容,在这时我们使用它的SystemHandleInformation(0x10),来完成文件句柄的操作。
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation, // 0
SystemProcessorInformation, // 1
SystemPerformanceInformation, // 2
…
SystemHandleInformation, // 16
…
SystemSessionProcessesInformation // 53
} SYSTEM_INFORMATION_CLASS;
ZwQueryInformationFile可以根据参数FileInformationClass的不同值来返回不同的类型,在这里我们使用FileInformationClass=FileInformationClass来得到FILE_NAME_INFORMATION,从而得到文件句柄指向的文件名,下面是它的结构定义。
typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
因为需要在Ring3上使用DDK提供的函数,我们需要导出这些两个函数,下面是导出函数的示例代码:
{
g_hNtDLL = LoadLibrary( "ntdll.dll" );
if ( !g_hNtDLL )
{
return FALSE;
}
ZwQuerySystemInformation =
(ZWQUERYSYSTEMINFORMATION)GetProcAddress( g_hNtDLL, "ZwQuerySystemInformation");
if( ZwQuerySystemInformation == NULL)
{
return FALSE;
}
ZwQueryInformationFile =
(ZWQUERYINFORMATIONFILE)GetProcAddress( g_hNtDLL, "ZwQueryInformationFile");
if( ZwQueryInformationFile == NULL)
{
return FALSE;
}
}
我们先来使用ZwQuerySystemInformation函数枚举系统中打开的所有文件的句柄,枚举出的信息将包含如下结构:
typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
ObjectTypeNumber定义了句柄所属对像的类型,文件的ObjectType对不同的操作系统是不同的,所以需要先找到当前操作系统所定义的ObjectType值,这样才能在枚举出的众多句柄信息中找到哪些是文件句柄信息。通用的方法是我们CreateFile打开空设备NUL,记下它的句柄,用来比较。
UCHAR GetFileHandleType()
{
HANDLE hFile;
PSYSTEM_HANDLE_INFORMATION Info;
ULONG r;
UCHAR Result = 0;
hFile = CreateFile("NUL", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
Info = GetInfoTable(SystemHandleInformation);
if (Info)
{
for (r = 0; r < Info->uCount; r++)
{
if (Info->aSH[r].Handle == (USHORT)hFile &&
Info->aSH[r].uIdProcess == GetCurrentProcessId())
{
Result = Info->aSH[r].ObjectType;
break;
}
}
HeapFree(hHeap, 0, Info);
}
CloseHandle(hFile);
}
return Result;
}
现在知道了句柄的类型就可以枚举系统中打开的文件了。首先用句柄获取打开的文件名:
typedef struct _NM_INFO
{
HANDLE hFile;
FILE_NAME_INFORMATION Info;
WCHAR Name[MAX_PATH];
} NM_INFO, *PNM_INFO;
// 因为在在线程中取得文件名
DWORD WINAPI
GetFileNameThread(PVOID lpParameter)
{
PNM_INFO NmInfo = lpParameter;
IO_STATUS_BLOCK IoStatus;
int r;
NtQueryInformationFile(NmInfo->hFile, &IoStatus, &NmInfo->Info,
sizeof(NM_INFO) - sizeof(HANDLE), FileNameInformation);
return 0;
}
void CFileProcess::GetFileName(HANDLE hFile, PCHAR TheName)
{
HANDLE hThread;
PNM_INFO Info = new NM_INFO;
char namebuf[2000] = {0};
Info->Info = (PFILE_NAME_INFORMATION)namebuf;
Info->hFile = hFile;
Info->nRet = 0x00;
// 在对打开的句柄调用ZwQueryInformationFile时,调用线程会等待PIPE中的消息
// 如果PIPE中没有消息时,线程可能会永久挂起,所以使用一个等待超时来打开句柄
hThread = CreateThread(NULL, 0, GetFileNameThread, Info, 0, NULL);
if (WaitForSingleObject(hThread, 100) == WAIT_TIMEOUT)
TerminateThread(hThread, 0);
CloseHandle(hThread);
// 调用句柄失败
if( Info->nRet == 0x00)
{
delete Info;
return ;
}
// 加上盘符
wchar_t volume = GetVolumeName(hFile);
if (volume != L'!')
{
wchar_t outstr[1000] = L"A:";
outstr[0] = volume;
memcpy(&outstr[2], Info->Info->FileName, Info->Info->FileNameLength);
outstr[2+Info->Info->FileNameLength] = 0;
WideCharToMultiByte(CP_ACP, 0, outstr, 2+Info->Info->FileNameLength, TheName, MAX_PATH, NULL, NULL);
}
delete Info;
return ;
}
下面代码片段用来枚举打开的文件:
{
// 取得操作系统文件句柄定义类型
UCHAR ObFileType = GetFileHandleType();
// 取得系统中打开的文件句柄列表
PULONG buf = GetHandleList();
if (buf == NULL)
return ;
Info = (PSYSTEM_HANDLE_INFORMATION)&buf[1];
if (Info)
{
for (r = 0; r < buf[0]; r++, Info++)
{
if (Info->ObjectTypeNumber == ObFileType && Info->ProcessId == dwProcessID)
{
hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, Info->ProcessId);
if (hProcess)
{
// 复制句柄到当前进程中,这样方便对当前进程句柄取出文件名
// 因为共享一个FileObject,这两个文件句柄对像将由两个进程共享
if ( DuplicateHandle( hProcess, (HANDLE)Info->Handle,
GetCurrentProcess(), &hFile, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
GetFileName(hFile, Name);
// 取得文件信息到链表中
if( strlen( Name)>0)
{
AfxTrace("PID=%d FileHandle %d FileName=%s", Info->ProcessId, Info->Handle, Name);
// 在这里加入你要保存的文件句柄信息
}
CloseHandle(hFile);
}
CloseHandle(hProcess);
}
}
}
}
}
2.3使用远线程方法关闭进程加载的模块和打开的文件
通过枚举进程加载的模块信息和打开的文件信息,我们已经得到系统中加载的DLL和文件名信息,以下是我们在链表中保存的信息:
{
DWORD ProcessID // 进程PID
BYTE nHandleType // 句柄类型是文件还是加载的DLL
Char strFileName[MAX_PATH] // 文件名
}
如果我们需要关闭正在打开的文件,只需要在这个链表中以文件名进行查找,即得到打开文件的进程PID。怎么才能通知别的进程关闭相应的句柄呢,我们通过跨进程去关闭句柄是很困难的,不如直接注入代码到需要的进程中,然后直接关闭句柄就行了。
需要再遍写一个DLL用来注入到进程中通知进程关闭文件句柄。这个DLL不需要做别的处理,只需要在加载的地方根据不同的句柄类型使用不同的方法进行关闭即可。下面是注入到进程的DLL执行的关闭句柄函数:
Void CloseHandel( PVOID pHandle, BYTE nHandleType)
{
If(HandleType = HANDLE_FILE)
FreeLibrary((HMODULE)pHandle);
else
CloseHandle((HANDLE)pHandle);
}
在DllMain中调用关闭句柄的函数:
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
DWORD nHandle=0;
BYTE nType=0;
TRACE0("MOPER.DLL Initializing!\n");
AfxMessageBox("MOPER.DLL Initializing!");
// 从碎甲程序所生成的文件句柄映射文件中取出要关闭的句柄信息
// 方法很多我在这里直接用共享文件实现的,就不写出代码了
GetHandle( nHandle, nType)
// 关闭句柄
CloseHandel((PVOID)nHandle, nType);
...
}
...
}
下面示例取出通过文件句柄链表中的PID,使用远程注入的方法向进程注入关闭句柄的DLL
{
HANDLE hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | //允许远程创建线程
PROCESS_VM_OPERATION | //允许远程VM操作
PROCESS_VM_WRITE,//允许远程VM写
FALSE, dwProcessId);
if( hRemoteProcess == NULL)
return FALSE;
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");
int nLen = (strlen( pszLibFile)+1)*sizeof(char);
char * pszLibFileRemote = (char *) VirtualAllocEx( hRemoteProcess, NULL, nLen, MEM_COMMIT, PAGE_READWRITE);
if( pszLibFileRemote != NULL &&
pfnStartAddr !=NULL)
{
if( WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (PVOID) pszLibFile, nLen, NULL))
{
HANDLE hThread = CreateRemoteThread( hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL);
if( !hThread)
{
WaitForSingleObject(hThread, INFINITE);
bRet = TRUE;
CloseHandle(hThread);
}
}
VirtualFreeEx(hRemoteProcess, pszLibFileRemote, 0, MEM_RELEASE);
}
CloseHandle( hRemoteProcess);
}
三.备注
对查找文件句柄的方法,参考了鄙人拙译(http://greatdong.blog.edu.cn)的“如何操作被占用文件”在此表示感谢。使用了Jeffrey在《Windows核心编程》一书中提供的CToolhelp类,用它可以完成进程加载信息的分析功能。
http://www.xfocus.net/articles/200708/935.html
-
exe与dll的自我更新
2012-07-26 15:33:01exe与dll的自我更新 ...在改写一个软件的自动更新程序时遇到一个问题 ...exe与dll在载入的时候是不能覆盖与删除的... ...自动更新的时候,如何把用http/ftp下载下来的新版本替换旧版本 ...b.exe 功能就是 将a.e
在改写一个软件的自动更新程序时遇到一个问题exe与dll的自我更新
exe与dll在载入的时候是不能覆盖与删除的...
自动更新的时候,如何把用http/ftp下载下来的新版本替换旧版本
第一种是最老土的办法:
假设a.exe要更新自己, down下来为a.exe.upd, 关闭自己,并execute一个第三方程序b.exe,
b.exe 功能就是 将a.exe.upd拷贝替换a.exe,再execute a.exe
优点:用几个简单的api就能搞定,基本上没什么难度...许多软件/游戏的自动更新程序用这种办法
缺点:适应性差,不能用于被别的程序占用文件的改写,只能用于exe文件,而且名称之类相对固定,需要第三方程序
第二种重启计算机大法
一般的安装程序都用此法,象驱动程序,系统软件安装,均提示需要重启电脑生效,
这种方法涉及到一个关键的API ::MoveFileEx 些函数详见MSDN
BOOL MoveFileEx(
LPCTSTR lpExistingFileName,
LPCTSTR lpNewFileName,
DWORD dwFlags
);
它的第三个参数使用
MOVEFILE_DELAY_UNTIL_REBOOT标志与MOVEFILE_REPLACE_EXISTING标志时
将在电脑启动时,自动替换文件...
以下是半伪半真代码...
a.exe 下载新版本a.exe.upd
if succeed(deletefile( a.exe))
movefile(a.exe.upd,a.exe);//如果删除成功,直接替换
else
{
MoveFileEx("'a.exe", "a.exe.upd",MOVEFILE_DELAY_UNTIL_REBOOT|MOVEFILE_REPLACE_EXISTING);
MessageBox("restart computer, yes/no?");
}
优点:适用性强,基本上能处理任何类型和任何情况的文件,非常保险
缺点:要重启计算机
第三种方法,也是我试过很多种后,使用的办法
前面说过exe与dll在载入的时候是不能覆盖与删除的,但是它能被改名
a.exe 下载新版本a.exe.upd
先将a.exe改成a.exe.tmp,
现在a.exe.tmp是不能被删除与覆盖的,
而a.exe这个文件不存在了
将a.exe.upd改名为a.exe
再关闭自己,重新启动a.exe,这时a.exe已经是新版的了
DeleteFile("a.exe.tmp");//以防万一,删除a.exe.tmp
Rename("a.exe","a.exe.tmp");
if SUCCEED(Rename("a.exe.upd","a.exe")){
Execute("a.exe");
CloseSelf();
}
else{
//特殊情况,连a.exe.tmp都被占用了,按第二种方法重启处理吧
}
优点:自己搞定,简单明了
缺点:不能用于被别的程序占用文件的改写,只能用于exe或者dll文件 -
21天学通javascript(第2版)(顾宁燕) pdf扫描版
2014-09-26 12:40:116.1 函数的功能 123 6.2 函数的定义 123 6.2.1 函数的普通定义方式 123 6.2.2 函数的变量定义方式 126 6.2.3 函数的指针调用方式 127 6.2.4 认识函数参数 128 6.2.5 认识arguments对象 128 6.3 函数返回类型 ... -
小学语文汉字记忆训练系统正式特惠版 V5.1D
2013-11-30 08:54:18在不断发展的信息技术条件下如何实现辅助汉字学习提高学习效率的软件功能? 希望能有更多的同仁参与我的研究,为中国汉字的教学,为中国文化传遍世界做出贡献! 小学语文生字记忆训练系统,是学习与记忆生字的最佳... -
应急响应-powershell挖矿
2019-02-10 15:43:24不过,他警告说,挖矿软件的编程者有能力改写恶意软件,来规避这个检测方法。 监控自己的网站是否被植入挖矿劫持代码。 Farral警告说,挖矿劫持者正设法在Web服务器上植入一些Javascript代码。服务器本身并不是其... -
Qt Creator 的安装和hello world 程序+其他程序的编写--不是一般的好
2011-01-28 17:02:08我们按下按钮,会弹出一个对话框,无论如何关闭这个对话框,都会回到主窗口。 实现原理: 程序里我们先建立一个主工程,作为主界面,然后再建立一个对 话框类,将其加入工程中,然后在程序中调用自己新建的对话框类... -
bat批处理文件实现复制、删除、创建文件夹、执行程序、打开文件
2014-12-15 12:28:40XCOPY 还有众多的功能, 是加参数来完成的。上面的/s /e 参数的作用分别是把子目录和空目录都复制过去,一些使用举例和参数说明如下: 1、如只是单纯地复制 E:\ 盘上所有文件到 D:\ 盘上,就输入“ xcopy e:\*.* d:... -
windows驱动开发技术详解-part2
2013-07-06 20:49:34这是书的光盘。共分为两个部分,这是第一部分。 本书由浅入深、循序渐进地介绍了Windows驱动程序的开发方法与调试技巧。本书共分23章,内容涵盖了 Windows操作系统的基本...后本章还介绍了如何对IRP的超时情况进行... -
IPv6.rar
2012-07-25 17:07:33ICMP代替了ARP的功能,被请求节点的组播地址被节点用来获得相同本地链路上邻居节点的链路层地址 2、用于重复地址检测DAD,在使用无状态自动配置将某个地址配置为自已的IPV6地址之前,节点利用DAD 验证在其本地链路... -
[2020.3.31] A: 新增debug 字段,用于开启/关闭 setState 时的 console。 导航 全局状态开始 安装及引入 实例化 App 中注入 页面上使用 修改状态 修改状态注意事项 页面周期监听 全局分享 全局方法 性能...
-
c# 加密和解密相关代码
2011-09-06 11:04:59添加两个Button 控件,分别用来实现利用ROT13算法加密和解密数据的功能。 (3)程序主要代码如下: public string ROT13Encode(string InputText) { char tem_Character; //存储临时字符 int UnicodeChar; //存储... -
DBX260中文说明书
2013-04-24 11:07:35260 DriveRackÔ的功能按钮允许访问260 DriveRackÔ的所有编辑和导航功能。 输入仪表 260 DriveRackÔ为用户提供了2个独立的12段LightpipeÔ输入仪表,其量程范围为-30~ +20dBu。注意:这些仪表可以被校准,... -
Visual C++程序员实用大全(精华版).(水利水电.邓劲生.张晓明译).part3
2016-06-21 21:11:38389 MFC是如何在Visual Studio中实现的 390 调用Visual Studio向导创建一个基于MFC的程序 391 引入Cobiect 392 应用程序结构类 393 使用对象类 394 文件服务类 395 使用设备场景类 396 绘图对象类 397 控件、支持、... -
Visual C++程序员实用大全(精华版).(水利水电.邓劲生.张晓明译).part4
2016-06-21 21:13:27389 MFC是如何在Visual Studio中实现的 390 调用Visual Studio向导创建一个基于MFC的程序 391 引入Cobiect 392 应用程序结构类 393 使用对象类 394 文件服务类 395 使用设备场景类 396 绘图对象类 397 控件、支持、... -
Visual C++程序员实用大全(精华版).(水利水电.邓劲生.张晓明译).part1
2016-06-21 21:05:54389 MFC是如何在Visual Studio中实现的 390 调用Visual Studio向导创建一个基于MFC的程序 391 引入Cobiect 392 应用程序结构类 393 使用对象类 394 文件服务类 395 使用设备场景类 396 绘图对象类 397 控件、支持、... -
Visual C++程序员实用大全(精华版).(水利水电.邓劲生.张晓明译).part2
2016-06-21 21:09:54389 MFC是如何在Visual Studio中实现的 390 调用Visual Studio向导创建一个基于MFC的程序 391 引入Cobiect 392 应用程序结构类 393 使用对象类 394 文件服务类 395 使用设备场景类 396 绘图对象类 397 控件、支持、... -
如何自定义Operator //定义一个继承自com.ql.util.express.Operator的操作符 public class JoinOperator extends Operator{ public Object executeInner(Object[] list) throws Exception { Object opdata1 = ...
-
sql 根据唯一索引批量添加或者更新
-
阿里云虚拟主机数据库管理取消线上登录,需下载客户端
-
Unity ILRuntime框架设计
-
大数据实体解析:大数据实体解析-源码
-
如何在渭南找到专业的微信小程序外包团队或者工作室?
-
SecureCRT 连接 GNS3/Linux 的安全精密工具
-
基于Qt的LibVLC开发教程
-
JavaCollectionFramework_2-源码
-
UBUNTU安装之后要配置的内容
-
nlw04:aplicação“ move.it”-Desenvolvido durante在火箭队的下一个级别周-源码
-
MySQL 高可用工具 heartbeat 实战部署详解
-
JMETER 性能测试基础课程
-
linux查看硬盘分区大小,查看活动的进程
-
Vue watch与watchEffect的区别
-
FTP 文件传输服务
-
pom.xml mvn package expected START_TAG or END_TAG not TEXT
-
PAT 甲级 1011 World Cup Betting
-
智能停车场云平台(附vue+SpringBoot前后端项目源码)
-
EL&JSTL笔记
-
投资组合:投资组合网站-源码