首页
社区
课程
招聘
[原创] C# 万金油框架之网页操控
2019-12-6 22:26 5728

[原创] C# 万金油框架之网页操控

2019-12-6 22:26
5728
0x00-----------------------------前言 
        此文为基础篇:对于很多个人的C#程序来说只是需要快速的实现功能,然而现实中你却需要在细节上消耗许多时间,比如说GUI,控件,非功能BUG等. 我这里就把我的一些框架和经验分享出来。我拿操纵网页这个功能来说,是因为这是我大学期间积累的经验,并且在学校和刚工作的时期对你有非常的大的帮助,前期你基本要和网页打交道。

那么这就开始,万事开头难,先了解一下我写程序的流程:


在大概知道流程之后,最重要的第一步。。。。。其实不在这个流程里。 是存在于Program.cs里的主程序入口。。。要防止程序多开!置顶已经打开的程序,弹出提醒。如果有错误,生成日志。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Windows.Forms;
using System.IO;

namespace WebAAA
{

   public  static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {

            try
            {
                //处理未捕获的异常   
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                //处理UI线程异常   
                Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
                //处理非UI线程异常   
                AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
                bool fuckingme;
                Process instance = RunningInstance();
                System.Threading.Mutex webaaa = new System.Threading.Mutex(true, "lemonzdemon", out fuckingme);
                //if (instance == null)
                //{
                if (fuckingme)
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                    webaaa.ReleaseMutex();
                }
                else
                {
                    HandleRunningInstance(instance);
                    //MessageBox.Show("我已经运行啦~~", "主人您好:", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception ex)
            {
                string str = "";
                string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n";

                if (ex != null)
                {
                    str = string.Format(strDateInfo + "异常类型:{0}\r\n异常消息:{1}\r\n异常信息:{2}\r\n",
                         ex.GetType().Name, ex.Message, ex.StackTrace);
                }
                else
                {
                    str = string.Format("应用程序线程错误:{0}", ex);
                }
                writeLog(str);
                MessageBox.Show("发生程序错误,请把Errlog目录的文件发送给作者! \n\n Errlog.txt能帮助作者修复程序~\n\n作者邮箱:************@qq.com", "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

       #region  确保程序只运行一个实例
         private static Process RunningInstance()
         {
             Process current = Process.GetCurrentProcess();
             Process[] processes = Process.GetProcessesByName(current.ProcessName);
             //遍历与当前进程名称相同的进程列表  
             foreach (Process process in processes)
             {
                 //如果实例已经存在则忽略当前进程  
                 if (process.Id != current.Id)
                 {
                     //保证要打开的进程同已经存在的进程来自同一文件路径
                    if (Assembly.GetExecutingAssembly().Location.Replace("//", "\\") == current.MainModule.FileName)
                     {
                         //返回已经存在的进程
                         return process;
                         
                     }
                 }
             }
             return null;
         }
 
         private static void HandleRunningInstance(Process instance)
         {
             MessageBox.Show("我已经运行啦~~", "主人您好:", MessageBoxButtons.OK, MessageBoxIcon.Information);
             ShowWindowAsync(instance.MainWindowHandle, 1);  //调用api函数,正常显示窗口
             SetForegroundWindow(instance.MainWindowHandle); //将窗口放置最前端
         }
         [DllImport("User32.dll")]
         private static extern bool ShowWindowAsync(System.IntPtr hWnd, int cmdShow);
         [DllImport("User32.dll")]
         private static extern bool SetForegroundWindow(System.IntPtr hWnd);
         #endregion
             static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
        {
            
            string str = "";
            string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n";
            Exception error = e.Exception as Exception;
            if (error != null)
            {
                str = string.Format(strDateInfo + "异常类型:{0}\r\n异常消息:{1}\r\n异常信息:{2}\r\n",
                     error.GetType().Name, error.Message, error.StackTrace);
            }
            else
            {
                str = string.Format("应用程序线程错误:{0}", e);
            }
            writeLog(str);
            MessageBox.Show("发生程序错误,请把Errlog目录的文件发送给作者! \n\n Errlog.txt能帮助作者修复程序~\n\n作者邮箱:**********@qq.com", "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            string str = "";
            Exception error = e.ExceptionObject as Exception;
            string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n";
            if (error != null)
            {
                str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆栈信息:{1}", error.Message, error.StackTrace);
            }
            else
            {
                str = string.Format("Application UnhandledError:{0}", e);
            }
            writeLog(str);
            MessageBox.Show("发生程序错误,请把Errlog目录的文件发送给作者! \n\n Errlog.txt能帮助作者修复程序~\n\n作者邮箱:**********@qq.com", "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        /// 写文件
        static void writeLog(string str)
        {
            if (!Directory.Exists("ErrLog"))
            {
                Directory.CreateDirectory("ErrLog");
            }

            using (StreamWriter sw = new StreamWriter(@"ErrLog\ErrLog.txt", true))
            {
                sw.WriteLine(str);
                sw.WriteLine("---------------------------------------------------------");
                sw.Close();
            }
        }
    }

}
    

0x01-----------------------------主窗体

第一步完成后,我们就可以开始流程了。引用文件头就不说了,主函数开始我们主要做的就是控制窗体和内核浏览器。这里我想说的是,必须控制C#的版本和内核浏览器的版本,不然每台机器呈现的效果都不一样。 主窗口的样式定义,webBrowser控件样式的定义,程序的开始和结束动画,都是很好的氛围。主程序的背景图片主要用webBrowser覆盖,因为我一直选择用网页做程序的背景图片,除了离线模式的静态图,这样不但能随时更换,样式也多。

public Form1()
        {
            InitializeComponent();
            AnimateWindow(this.Handle, 800, AW_BLEND + AW_CENTER + AW_ACTIVATE);
            this.MaximizeBox = false; 
            this.AutoSizeMode = AutoSizeMode.GrowAndShrink; // 禁用手动调整大小。
            this.SizeGripStyle = SizeGripStyle.Hide; // 隐藏调整大小手柄。
            this.StartPosition = FormStartPosition.CenterScreen; // 在桌面居中显示。
            webBrowser1.ScriptErrorsSuppressed = true;  //禁用错误脚本提示   
            webBrowser1.IsWebBrowserContextMenuEnabled = false;  //禁用右键菜单   
            webBrowser1.WebBrowserShortcutsEnabled = false;  //禁用快捷键
            webBrowser1.AllowWebBrowserDrop = false; //禁止拖拽
            webBrowser1.ScrollBarsEnabled = false; //禁止滚动条
 
        } 

关闭窗口时渐隐效果(开头和结尾先弄好,程序启动可以新建窗体填充图片,新建窗体可见度逐渐为0,然后显示主窗体,可以做成广告):
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
                AnimateWindow(this.Handle, 800, AW_BLEND + AW_SLIDE + AW_CENTER + AW_HIDE);
                Environment.Exit(Environment.ExitCode);
        }
        private void XFormMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            //动态关闭窗体
            AnimateWindow(this.Handle, 800, AW_SLIDE + AW_HIDE + AW_CENTER);
        }

0x02-----------------------------初始化
第二部申明各种常量和变量,引用WINAPI的DLL。 为之后使用基本的WINAPI做准备。
private string userAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)";

        [DllImport("urlmon.dll", CharSet = CharSet.Unicode)]
        private static extern int UrlMkSetSessionOption(int dwOption, string pBuffer, int dwBufferLength, int dwReserved);
        private const int UrlmonOptionUseragent = 0x10000001;

        [DllImportAttribute("user32.dll")]
        private static extern bool AnimateWindow(IntPtr hwnd, int dwTime, int dwFlags);
        /*
        1. AW_SLIDE : 使用滑动类型, 默认为该类型. 当使用 AW_CENTER 效果时, 此效果被忽略
        2. AW_ACTIVE: 激活窗口, 在使用了 AW_HIDE 效果时不可使用此效果
        3. AW_BLEND: 使用淡入效果
        4. AW_HIDE: 隐藏窗口
        5. AW_CENTER: 与 AW_HIDE 效果配合使用则效果为窗口几内重叠,  单独使用窗口向外扩展.
        6. AW_HOR_POSITIVE : 自左向右显示窗口
        7. AW_HOR_NEGATIVE: 自右向左显示窗口
        8. AW_VER_POSITVE: 自顶向下显示窗口
        9. AW_VER_NEGATIVE : 自下向上显示窗口
        */
        public const Int32 AW_HOR_POSITIVE = 0x00000001;
        public const Int32 AW_HOR_NEGATIVE = 0x00000002;
        public const Int32 AW_VER_POSITIVE = 0x00000004;
        public const Int32 AW_VER_NEGATIVE = 0x00000008;
        public const Int32 AW_CENTER = 0x00000010;
        public const Int32 AW_HIDE = 0x00010000;
        public const Int32 AW_ACTIVATE = 0x00020000;
        public const Int32 AW_SLIDE = 0x00040000;
        public const Int32 AW_BLEND = 0x00080000;

   [System.Runtime.InteropServices.DllImport("User32.dll")]
        private static extern bool IsIconic(IntPtr hWnd);
          [DllImport("user32.dll", CharSet = CharSet.Auto)]
       private  static extern int SetWindowPos(IntPtr hWnd, int  hWndInsertAfter, int x, int y, int Width, int Height, int flags);
        [DllImport("user32.dll", CharSet = CharSet.Auto)] //设置窗体位置和高度
        private static extern System.IntPtr GetForegroundWindow();

0x03-----------------------------功能函数
第三部开始写各种功能函数,因为是个人程序,代码不可能很多,没必要封装函数。这样写在一页的函数会让外人看起来很多,很复杂。。。很多年前老师也说太乱。。话没毛病。。但是。。你TM倒是来帮我写啊。。。所以不要管那些,自己清楚自己的函数在哪就行了。 毕竟日后开发的时候,自己知道在哪,改好了就完了。  你开发的时候很难把它开源,一旦开源你就没啥开发的动力了。

查找窗体函数:
class FindWindow
        {
            [DllImport("user32")]
            [return: MarshalAs(UnmanagedType.Bool)]
            //IMPORTANT : LPARAM  must be a pointer (InterPtr) in VS2005, otherwise an exception will be thrown
            private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
            //the callback function for the EnumChildWindows
            private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

            //if found  return the handle , otherwise return IntPtr.Zero
            [DllImport("user32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Unicode)]
            private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

            private string m_classname; // class name to look for
            private string m_caption; // caption name to look for

            private DateTime start;
            private int m_timeout;//If exceed the time. Indicate no windows found.

            private IntPtr m_hWnd; // HWND if found
            public IntPtr FoundHandle
            {
                get { return m_hWnd; }
            }

            private bool m_IsTimeOut;
            public bool IsTimeOut
            {
                get { return m_IsTimeOut; }
                set { m_IsTimeOut = value; }
            }

            // ctor does the work--just instantiate and go
            public FindWindow(IntPtr hwndParent, string classname, string caption, int timeout)
            {
                m_hWnd = IntPtr.Zero;
                m_classname = classname;
                m_caption = caption;
                m_timeout = timeout;
                start = DateTime.Now;
                FindChildClassHwnd(hwndParent, IntPtr.Zero);
            }

         
            private bool FindChildClassHwnd(IntPtr hwndParent, IntPtr lParam)
            {
                EnumWindowProc childProc = new EnumWindowProc(FindChildClassHwnd);
                IntPtr hwnd = FindWindowEx(hwndParent, IntPtr.Zero, m_classname, m_caption);
                if (hwnd != IntPtr.Zero)
                {
                    this.m_hWnd = hwnd; // found: save it
                    m_IsTimeOut = false;
                    return false; // stop enumerating
                }
                DateTime end = DateTime.Now;

                if (start.AddSeconds(m_timeout) < end)
                {
                    m_IsTimeOut = true;
                    return false;
                }
                EnumChildWindows(hwndParent, childProc, IntPtr.Zero); // recurse  redo FindChildClassHwnd
                return true;// keep looking
            }
        }

执行CMD:
public string executeCmd(string Command)
        {
            Process process = new Process
            {
                StartInfo = { FileName = " cmd.exe ", UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, CreateNoWindow = true }
            };
            process.Start();
            process.StandardInput.WriteLine(Command);
            process.StandardInput.WriteLine("exit");
            process.WaitForExit();
            string str = process.StandardOutput.ReadToEnd();
            process.Close();
            return str;
        }

防止网页跳转:
private void wB_MainBrowser_NewWindow(object sender, CancelEventArgs e)
        {
            e.Cancel = true;
            try
            {
                string url = this.webBrowser1.Document.ActiveElement.GetAttribute("href");
                this.webBrowser1.Url = new Uri(url);
            }
            catch
            {
            }
        }

        private void SetAllWebItemblank(HtmlElementCollection items)
        {
            try
            {
                foreach (HtmlElement item in items)
                {
                    if (item.TagName.ToLower().Equals("iframe", StringComparison.OrdinalIgnoreCase) == false)
                    {
                        try
                        {
                            item.SetAttribute("target", "_blank");
                        }
                        catch
                        { }
                    }
                    else
                    {
                        try
                        {
                            HtmlElementCollection fitems = item.Document.Window.Frames[item.Name].Document.All;
                            this.SetAllWebItemblank(fitems);
                        }
                        catch
                        { }
                    }
                }
            }
            catch
            {
            }
        }
        private void SetAllWebItemSelf(HtmlElementCollection items)
        {
            try
            {
                foreach (HtmlElement item in items)
                {
                    if (item.TagName.ToLower().Equals("iframe", StringComparison.OrdinalIgnoreCase) == false)
                    {
                        try
                        {
                            item.SetAttribute("target", "_self");
                        }
                        catch
                        { }
                    }
                    else
                    {
                        try
                        {
                            HtmlElementCollection fitems = item.Document.Window.Frames[item.Name].Document.All;
                            this.SetAllWebItemSelf(fitems);
                        }
                        catch
                        { }
                    }
                }
            }
            catch
            {
            }
        }

对网页注入JS和CSS
    private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {

            if (webBrowser1.DocumentTitle.IndexOf("你网站的标题") > -1)
            {
                try
                {
                    webBrowser1.WebBrowserShortcutsEnabled = true;
                    string fixthat = @"background-color: #6CF;
	height: 400px;
	width: 600px;
	border: 1px solid #666;
	background-image: url(http://自己要用的网站,也是程序的背景, 此段也是控制主窗口的显示/backpic.aspx);
	background-repeat: no-repeat;
	position:absolute;
	left:50%;
	top:50%;
	margin-top:-200px;
	margin-left: -300px;";
                    HtmlElementCollection godlike = webBrowser1.Document.Body.All;
                    string suckyou = @"<span id='suckyou' style='position: absolute;left: 6px;top: 6px;color:rgb(0, 0, 0);display: inline-block;width: 160px;white-space: nowrap;font-family:微软雅黑;font-size:16px;font-weight: bold;'>柠檬版Web      :D</span>";
                     //你自己需要对网页注入的代码JS或者CSS
                    foreach (HtmlElement X in godlike)
                    {
                        if (X.Parent.InnerText == "登录" || X.Parent.InnerText == "注销")
                        {
                            X.Parent.Parent.Parent.Style = fixthat;
                            X.Parent.Parent.FirstChild.NextSibling.NextSibling.FirstChild.Style += "display:none"; //对网页子元素进行修改
                            X.Parent.Parent.FirstChild.NextSibling.NextSibling.FirstChild.OuterHtml += suckyou;
                        }
                    }
            }

0x04-----------------------------按钮功能

按钮功能根据自己的需求写吧,这里之做一个示范
private void button1_Click(object sender, EventArgs e)
        {
            HtmlElementCollection godlike = webBrowser1.Document.Body.All;
            string webaaaurl = @"http://链接的网址
            this.webBrowser1.Navigate(webaaaurl); //导航到此
         try // 这个是我当时写的读取配置文件
         {
             string str1;
             FileStream fs = File.OpenRead(@"bootinfo.txt");
             StreamReader sr = new StreamReader(fs);
             str1 = sr.ReadToEnd();
             fs.Close();
             string user  = *******;
             string pwd  = *******;
             foreach (HtmlElement X in godlike)
             {
                 if (X.Parent.InnerText == "用户名:")
                 {
                     HtmlElement tbUserid = X.Parent.FirstChild.NextSibling; //查找元素
                     HtmlElement tbPasswd = X.Parent.NextSibling.FirstChild.NextSibling.NextSibling;
                     tbUserid.SetAttribute("value", user); //设置用户名和密码
                     tbPasswd.SetAttribute("value", pwd);
                 }
             }
             ListBoxLogs.AddCtrlValue(this, sysLogs, DateTime.Now.ToString("HH:mm:ss") + "-" + "Web客户端刷新完毕");
         }
         catch (Exception)
         {
             MessageBox.Show("喵~ 貌似您的bootinfo.txt有问题 或者 网站又升级了喵~╮(╯▽╰)╭ !", "友善提示ing :");  
         }
        }

0x05-----------------------------其他

第五部主要是一些鸡肋的东西,比如测试的功能,和一些比较简单的功能写在这里。 能用就用,不用就放着或者注释掉。比如说打开CMD执行参数,POWERSHELL执行参数。

执行CMD
Process.Start("explorer.exe", @"ftp://ftp.****.cn/");

查找和向其他窗口传送按键
 System.Windows.Forms.Application.DoEvents();
            FindWindow AAA = new FindWindow(IntPtr.Zero, null, "A客户端", 5); //查找其他窗口
            FindWindow DL = new FindWindow(AAA.FoundHandle, null, "登陆", 800);
            FindWindow ts = new FindWindow(IntPtr.Zero, null, "提示", 5);
            FindWindow qd = new FindWindow(ts.FoundHandle, null, "确定", 5);
if (AAA.FoundHandle == IntPtr.Zero)
            {
                MessageBox.Show("客户端没打开", "你妹的:");
                this.WindowState = FormWindowState.Minimized;
            }
else if (DL.FoundHandle != IntPtr.Zero && ts.FoundHandle != IntPtr.Zero)
            {
                //关闭提示窗口
                ShowWindow(ts.FoundHandle, 1);  //显示找到的窗口
                SendMessage(ts.FoundHandle, WM_SETFOCUS, 0, 0); //发送按键和消息
                SendMessage(ts.FoundHandle, WM_CLOSE, 0, 0);
                //链接客户端
                ShowWindow(AAA.FoundHandle, 1);
                SetWindowPos(AAA.FoundHandle, -1, 0, 0, 0, 0, 1 | 2);
                SetForegroundWindow(DL.FoundHandle);
                ShowWindowAsync(DL.FoundHandle, SW_RESTORE);
                SendMessage(DL.FoundHandle, WM_SETFOCUS, 0, 0);
                SendMessage(DL.FoundHandle, WM_LBUTTONDOWN, 0, 0);
            }

系统延时:
private void Delay(int Millisecond) //延迟系统时间,但系统又能同时能执行其它任务;
        {
            DateTime current = DateTime.Now;
            while (current.AddMilliseconds(Millisecond) > DateTime.Now)
            {
                Application.DoEvents();//转让控制权            
            }
            return;
        }

0x06-----------------------------结尾

这几步写完了,程序就已经能正常使用了,但是C#的尴尬有很多,你写好的软件等于说源码送给别人,你不得不进行加密和混淆。 一般都是网上找的混淆软件,先加基本压缩壳,再进行混淆。 C#对网页的操作很棒,代码可读性很强。你需要知道JAVASCRIPT/CSS,正则匹配,读/提参数。  这样写出来的程序,最小化在窗口干别的就行了。 前期上学和工作期间,肯定有大用处。 

[assembly: AssemblyTitle("Windows 服务主进程")]
[assembly: AssemblyDescription("Windows 服务主进程")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyProduct("Microsoft® Windows® Operating System")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved. ")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]   //很多年前连编译注释都给改了,防老师够了,哈哈。

之后网页的操作会渐渐对你没什么帮助,你需要搞数据库和WINAPI相关的东西。那是下一个层次。 比如说写病毒,爬虫,扫描之类的软件。 总而言之,通过这一套永久的复制粘贴,让你的程序迅速进入工作状态,前期打基础,为后面的底层操作打基础吧。

我记得之前有个人,用C#写了一个壳调用WINAPI搞内核软件什么,再也没有看见他发过。不知道软件是什么进度了,前不久AntiSpy开源了,也想看看那人后来怎么样了,反正C#真的好像一个躯壳,就像克隆人一样。希望这篇文章为那些初学者一些启发和指导作用吧。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工 作,每周日13:00-18:00直播授课

收藏
点赞3
打赏
分享
最新回复 (3)
雪    币: 3496
活跃值: (749)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kxzpy 2019-12-7 06:15
2
0
不错,收藏
雪    币: 1366
活跃值: (5584)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
supperlitt 2019-12-7 09:22
3
0
推荐你使用。cefsharp,可以控制的chrome浏览器。参考
https://github.com/cefsharp/CefSharp
https://github.com/supperlitt/th_cefsharp_httpwatch
雪    币: 292
活跃值: (153)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Dstlemoner 2019-12-7 16:02
4
0
supperlitt 推荐你使用。cefsharp,可以控制的chrome浏览器。参考 https://github.com/cefsharp/CefSharp https://github.com/supperlit ...
可以哦,如虎添翼。
游客
登录 | 注册 方可回帖
返回