2021年6月22日 星期二

[程式碼] 在Windows使用Python/C#監測檔案是否被修改

Python

import os, time, datetime
print("創立時間: " + datetime.datetime.fromtimestamp(os.path.getctime(file)).strftime("%Y-%m-%d %H:%M:%S"))
print("修改時間: " + datetime.datetime.fromtimestamp(os.path.getmtime(file)).strftime("%Y-%m-%d %H:%M:%S"))

程式執行效果如下





C#

using System.IO;

FileInfo f = new FileInfo(strFile);
DateTime dtCreate = f.CreationTime;
DateTime dtModify = f.LastWriteTime;

程式執行效果如下


2021年4月6日 星期二

[程式碼] 使用Excel + VBA實現通訊錄 (Tasker案例)

'ThisWorkbook
Private Sub Workbook_Open()
  shtApp.Activate
  UserForm1.Show
End Sub

'ShtApp
Private Sub Worksheet_activate()
  UserForm1.Show
End Sub


Private Sub Worksheet_Deactivate()
  UserForm1.Hide
End Sub


' UserForm
Dim gnDataRow As Long

Private Sub Userform_Initialize()
    gnDataRow = -1
End Sub

Private Sub SearchData(ByVal nSearchCol As Integer, ByVal strCondition As String)
    Dim row As Long
    
    listData.Clear
    
    For row = 2 To shtData.UsedRange.Rows.Count
    If InStr(shtData.Cells(row, nSearchCol).Value, strCondition) > 0 Then
      listData.AddItem Str(row) & vbTab & shtData.Cells(row, 1).Value & vbTab & shtData.Cells(row, 2).Value & vbTab & shtData.Cells(row, 3).Value & vbTab & shtData.Cells(row, 4).Value
    End If
  Next row
End Sub

Private Sub btnName_Click()
    SearchData 1, txtName.Text
End Sub

Private Sub btnMobile_Click()
    SearchData 2, txtMobile.Text
End Sub

Private Sub btnPhone_Click()
    SearchData 3, txtPhone.Text
End Sub

Private Sub btnAddr_Click()
    SearchData 4, txtAddr.Text
End Sub

Private Sub btnAdd_Click()
    Dim name As String, mobile As String, phone As String, addr As String
    Dim row As Long
    
    name = txtName.Text
    If "" = name Then
        MsgBox "請先輸入姓名", vbOKOnly, "資料新增"
        Exit Sub  ' 離開副程式
    End If
    
    mobile = txtMobile.Text
    phone = txtPhone.Text
    addr = txtAddr.Text
    
    For row = 2 To shtData.UsedRange.Rows.Count  ' 檢查是否有名字重複
      If shtData.Cells(row, 1).Value = name Then
        Exit For
      End If
    Next row
  
    If row <= shtData.UsedRange.Rows.Count Then
        If vbNo = MsgBox("名稱重複,是否確定加入?", vbYesNo, "名稱重複") Then
            Exit Sub  ' 離開副程式
        Else
            row = shtData.UsedRange.Rows.Count
        End If
    End If
    
    shtData.Cells(row, 1).Value = name
    shtData.Cells(row, 1).HorizontalAlignment = xlCenter
    
    shtData.Cells(row, 2).Value = mobile
    shtData.Cells(row, 2).HorizontalAlignment = xlCenter
    
    shtData.Cells(row, 3).Value = phone
    shtData.Cells(row, 3).HorizontalAlignment = xlCenter
    
    shtData.Cells(row, 4).Value = addr
    SearchData 1, ""
    gnDataRow = -1
End Sub

Private Sub btnModify_Click()
    If -1 = gnDataRow Then
        MsgBox "請先從列表中選擇資料", vbOKOnly, "資料修改"
        Exit Sub
    End If
    
    shtData.Cells(gnDataRow, 1).Value = txtName.Text
    shtData.Cells(gnDataRow, 1).HorizontalAlignment = xlCenter
    
    shtData.Cells(gnDataRow, 2).Value = txtMobile.Text
    shtData.Cells(gnDataRow, 2).HorizontalAlignment = xlCenter
    
    shtData.Cells(gnDataRow, 3).Value = txtPhone.Text
    shtData.Cells(gnDataRow, 3).HorizontalAlignment = xlCenter
    
    shtData.Cells(gnDataRow, 4).Value = txtAddr.Text
    
    SearchData 1, txtName.Text
    gnDataRow = -1
End Sub

Private Sub btnDelete_Click()
    If -1 = gnDataRow Then
        MsgBox "請先從列表中選擇資料", vbOKOnly, "資料刪除"
        Exit Sub
    End If
    
    shtData.Rows(gnDataRow).EntireRow.Delete
    SearchData 1, ""
    gnDataRow = -1
End Sub


Private Sub listData_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
    If listData.Text = "" Then
        Exit Sub
    End If
    
    Dim arrStr() As String
    arrStr = Split(listData.Text, vbTab)
    gnDataRow = Int(arrStr(0))
    txtName.Text = arrStr(1)
    txtMobile.Text = arrStr(2)
    txtPhone.Text = arrStr(3)
    txtAddr.Text = arrStr(4)
End Sub

[真實案例] 使用Excel + VBA實現通訊錄 (Tasker案例)

 今天我們要介紹如何使用Excel + VBA實現通訊錄APP

首先我們進入VBA編輯器畫面

按右鍵選擇插入自訂表單


先將表單的ShowModal改為False,如此一來可以一邊使用UserForm,一邊使用Excel功能否則UserForm出現時,Excel會沒辦法操作其他功能

接下來我們先將APP介面設計好

基本資料包括姓名、手機、住家電話與住址,並加入各自的搜尋按鈕

我們將搜尋功能包成一個函數,四種搜尋按鈕各自帶入比對欄位與參數

再來是新增、修改、刪除與資料ListBox

新增按鈕先檢查是否有輸入姓名,並確認名字是否有重複,若重複時確認使用者是否真的要新增資料,然後將資料加入最後一列

刪除與修改功能要先確定使用者有從listbox選中資料,方便我們知道要改的是哪列資料

接著我們在Excel開啟時,要顯示APP分頁,並且秀出表單

並且在分頁切換時,去顯示/隱藏表單



操作影片


[程式碼] 使用Python 爬取內政部戶政司提供之全國門牌資料 (PTT CodeJob案例)

import requests

url = "https://www.ris.gov.tw/info-doorplate/app/doorplate/dateQuery"


data = {

  "searchType": "date",

  "cityCode": "63000000",

  "tkt": "-1",

  "areaCode": "63000010",

  "village": "",

  "neighbor": "",

  "sDate": "001-01-01",

  "eDate": "110-03-25",

  "_includeNoDate": "on",

  "registerKind": "0",

  "floor": "",

  "lane": "",

  "alley": "",

  "number": "",

  "number1": "",

  "ext": "",

  "_search": "false",

  "nd": "1616602191259",

  "rows": "20",

  "page": "1",

  "sidx": "",

  "sord": "asc",

  "token": ""

}


r = requests.post(url, data=data)

r.encoding='utf-8'

f = open(r'dump.txt', 'w', encoding="utf-8")

f.write(r.text)

f.close()


[真實案例] 使用Python 爬取內政部戶政司提供之全國門牌資料 (PTT CodeJob案例)

今天我們要介紹如何使用Python爬取內政部戶政司提供之全國門牌資料

首先讓我們連到文章內的網址

點右鍵觀看程式碼,先搜尋"現有村里街路門牌查詢"關鍵字串

我們可以發現在網頁原始碼中,找不到該字串,因此可以判斷網頁某些內容是需要執行過Javascript後,才會是完整內容

在點選"以編釘日期、編釘類別查詢"按鈕後,來到縣市選擇頁面,但是我們發現網址並沒有改變,所以無法單純利用網址跳轉方式來操作

按下F12觀看網路操作,發現有進行一個POST動作

請求內容為使用日期作為搜尋條件

點選臺北市後,看到有對另外一個網址進行POST

請求內容除了剛才的日期以外,還多了一個城市編碼

填好想要的條件之後,點選搜尋


請求發出後,就會回應我們相關的內容

當我們點選下一頁時,POST的需求也跟著改變

我們已經找出資料是由dataQuery這個網址所回應,因此我們要爬資料只需要照著需求填寫,再利用POST功能取得資料就可以了

最後我們來比對一下網頁資料與抓下來的內容
v1 部分是門牌資料,v2是編訂日期,v3是編訂類別




操作影片



2021年3月30日 星期二

使用C#與Python實作遊戲修改大師

 首先我們編寫一支測試程式

按鈕每按一次將全域變數(Value)加1,並且將數值顯示在右邊標籤

右邊文本框在視窗初始化時,顯示全域變數的位址

程式流程如下

首先使用GetCurrentProcess取得修改程式控制碼,接著使用相關Windows API將權限提升

使用FindWindow找到視窗控制碼,再使用GetWindowsThreadProcessID得到ProcessID,最後再利用這個ID取得程序控制碼


搜尋目標數值前,我們先使用GetSystemInfor取得應用程式的記憶體上下限

再利用VirtualQueryEx確定記憶體區塊屬性為可讀可寫


如果條件都成立,使用ReadProcessMemory將整個記憶體區塊內容讀出,並比對數值是否為我們要的,如果是就記錄該記憶體位址

測試程式修改記憶體後,檢查記錄地址的記憶體內容數值是否依然匹配,若不匹配則移除該地址,直到只剩下一個地址

最後我們使用WriteProcessMemoroy去修改測試程式的記憶體數值

C#程式碼

[程式碼] C#修改程式記憶體

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;  // DllImport
using System.Diagnostics;  // Process
namespace RwMem
{
    // https://www.pinvoke.net/default.aspx
    public class AdjPriv  // 提升權限
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct TokPriv1Luid
        {
            public int Count;
            public long Luid;
            public int Attr;
        }
        [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
        static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, 
            ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
        [DllImport("kernel32.dll", ExactSpelling = true)]
        static extern IntPtr GetCurrentProcess();
        [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
        static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
        const int SE_PRIVILEGE_ENABLED = 0x00000002;
        const int TOKEN_QUERY = 0x00000008;
        const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
        const string SE_TIME_ZONE_NAMETEXT = "SeTimeZonePrivilege"; //http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
        public bool SetPriv()
        {
            try
            {
                bool retVal;
                TokPriv1Luid tp;
                IntPtr hproc = GetCurrentProcess();
                IntPtr htok = IntPtr.Zero;
                retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
                tp.Count = 1;
                tp.Luid = 0;
                tp.Attr = SE_PRIVILEGE_ENABLED;
                retVal = LookupPrivilegeValue(null, SE_TIME_ZONE_NAMETEXT, ref tp.Luid);
                retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
                return retVal;
            }
            catch (Exception ex)
            {
                throw;
                return false;
            }
        }
    }
    class Program
    {
        static List<IntPtr> liAddr = new List<IntPtr>();  // 記錄查找到的記憶體位址
        [StructLayout(LayoutKind.Sequential)]
        internal struct SYSTEM_INFO
        {
            internal ushort wProcessorArchitecture;
            internal ushort wReserved;
            internal uint dwPageSize;
            internal IntPtr lpMinimumApplicationAddress;
            internal IntPtr lpMaximumApplicationAddress;
            internal IntPtr dwActiveProcessorMask;
            internal uint dwNumberOfProcessors;
            internal uint dwProcessorType;
            internal uint dwAllocationGranularity;
            internal ushort wProcessorLevel;
            internal ushort wProcessorRevision;
        }
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern void GetSystemInfo(ref SYSTEM_INFO Info);  // 取得系統資訊
        [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);  // 尋找視窗標題
        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);  // 取得程序ID
        private enum ProcessAccessTypes
        {
            PROCESS_TERMINATE = 0x00000001,
            PROCESS_CREATE_THREAD = 0x00000002,
            PROCESS_SET_SESSIONID = 0x00000004,
            PROCESS_VM_OPERATION = 0x00000008,
            PROCESS_VM_READ = 0x00000010,
            PROCESS_VM_WRITE = 0x00000020,
            PROCESS_DUP_HANDLE = 0x00000040,
            PROCESS_CREATE_PROCESS = 0x00000080,
            PROCESS_SET_QUOTA = 0x00000100,
            PROCESS_SET_INFORMATION = 0x00000200,
            PROCESS_QUERY_INFORMATION = 0x00000400,
            STANDARD_RIGHTS_REQUIRED = 0x000F0000,
            SYNCHRONIZE = 0x00100000,
            PROCESS_ALL_ACCESS = PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_SET_SESSIONID | PROCESS_VM_OPERATION |
              PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_DUP_HANDLE | PROCESS_CREATE_PROCESS | PROCESS_SET_QUOTA |
              PROCESS_SET_INFORMATION | PROCESS_QUERY_INFORMATION | STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE
        }
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);
        [DllImport("kernel32.dll")]
        static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer,
            int dwSize, out IntPtr lpNumberOfBytesRead);
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer,
            Int32 nSize, out IntPtr lpNumberOfBytesWritten);
        public enum AllocationProtectEnum : uint
        {
            PAGE_EXECUTE = 0x00000010,
            PAGE_EXECUTE_READ = 0x00000020,
            PAGE_EXECUTE_READWRITE = 0x00000040,
            PAGE_EXECUTE_WRITECOPY = 0x00000080,
            PAGE_NOACCESS = 0x00000001,
            PAGE_READONLY = 0x00000002,
            PAGE_READWRITE = 0x00000004,
            PAGE_WRITECOPY = 0x00000008,
            PAGE_GUARD = 0x00000100,
            PAGE_NOCACHE = 0x00000200,
            PAGE_WRITECOMBINE = 0x00000400
        }
        public enum StateEnum : uint
        {
            MEM_COMMIT = 0x1000,
            MEM_FREE = 0x10000,
            MEM_RESERVE = 0x2000
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct MEMORY_BASIC_INFORMATION
        {
            public IntPtr BaseAddress;
            public IntPtr AllocationBase;
            public uint AllocationProtect;
            public IntPtr RegionSize;
            public uint State;
            public uint Protect;
            public uint Type;
        }
        [DllImport("kernel32.dll")]
        static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress,  // 查詢記憶體資訊
            out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength);
        static void ScanMemStep0(IntPtr hProcess, int nSize, int nValue)  // 從頭開始尋找記憶體並記錄匹配位址
        {
            SYSTEM_INFO stSysInfo = new SYSTEM_INFO();
            GetSystemInfo(ref stSysInfo);
            MEMORY_BASIC_INFORMATION stMemBasicInfo = new MEMORY_BASIC_INFORMATION();
            UInt64 BaseAddr = (UInt64)stSysInfo.lpMinimumApplicationAddress;
            UInt64 MaxAddr = (UInt64)stSysInfo.lpMaximumApplicationAddress;
            liAddr.Clear();
            while (BaseAddr < MaxAddr)
            {
                VirtualQueryEx(hProcess, (IntPtr)BaseAddr, out stMemBasicInfo, (uint)Marshal.SizeOf(stMemBasicInfo));
                if (stMemBasicInfo.Protect == (uint)AllocationProtectEnum.PAGE_READWRITE &&  // 可讀可寫
                    stMemBasicInfo.State == (uint)StateEnum.MEM_COMMIT)
                {
                    IntPtr bytesRead = IntPtr.Zero;
                    byte[] buffer = new byte[(UInt64)stMemBasicInfo.RegionSize];
                    ReadProcessMemory(hProcess, stMemBasicInfo.BaseAddress, buffer, (int)stMemBasicInfo.RegionSize, out bytesRead);
                    if(nSize == 4)
                    {
                        for (int i = 0; i < (int)stMemBasicInfo.RegionSize; i+=4)
                            if (BitConverter.ToInt32(buffer, i) == nValue)
                                liAddr.Add(stMemBasicInfo.BaseAddress + i);
                    }
                }
                BaseAddr += (UInt64)stMemBasicInfo.RegionSize;
            }
        }

        static void ScanMemStep1(IntPtr hProcess, int nSize, int nValue)  // 接續尋找變更資料後的記憶體
        {
            IntPtr bytesRead = IntPtr.Zero;
            byte[] buffer = new byte[nSize];
            for (int i = liAddr.Count-1; i >= 0; i--)
            {
                ReadProcessMemory(hProcess, liAddr[i], buffer, nSize, out bytesRead);
                if (nSize == 4)
                {
                    if (BitConverter.ToInt32(buffer, 0) != nValue)
                        liAddr.RemoveAt(i);
                }
            }
        }

        static void WriteMem(IntPtr hProcess, int nSize, int nValue)  // 修改記憶體內容
        {
            IntPtr bytesRead = IntPtr.Zero;
            byte[] buffer = BitConverter.GetBytes(nValue);
            if (1 != liAddr.Count)
                return;
            WriteProcessMemory(hProcess, liAddr[0], buffer, nSize, out bytesRead);
        }

        static void Main(string[] args)
        {
            AdjPriv ajdPriv = new AdjPriv();
            ajdPriv.SetPriv();
            IntPtr hWnd = FindWindowByCaption(IntPtr.Zero, "維京碼農");
            if(hWnd != IntPtr.Zero)
            {
                uint dwThreadID = 0;
                GetWindowThreadProcessId(hWnd, out dwThreadID);
                IntPtr hProcess = OpenProcess((uint)(ProcessAccessTypes.PROCESS_QUERY_INFORMATION |
                    ProcessAccessTypes.PROCESS_VM_READ | 
                    ProcessAccessTypes.PROCESS_VM_WRITE),
                    false,
                    (int)dwThreadID);
                while(true)
                {
                    Console.Write("Input Scan Step、Size And Value: ");
                    string str = Console.ReadLine();
                    string[] arrStr = str.Split(' ');
                    if(arrStr[0] == "0")
                    {
                        ScanMemStep0(hProcess, Convert.ToInt32(arrStr[1]), Convert.ToInt32(arrStr[2]));
                        Console.WriteLine("Count Of liAddr = {0}\n", liAddr.Count);
                    }
                    else if(arrStr[0] == "1")
                    {
                        ScanMemStep1(hProcess, Convert.ToInt32(arrStr[1]), Convert.ToInt32(arrStr[2]));
                        Console.WriteLine("Count Of liAddr = {0}\n", liAddr.Count);
                        if(liAddr.Count == 1)
                            Console.WriteLine("Addr Of Value = {0:X}\n", (int)liAddr[0]);
                    }
                    else if(arrStr[0] == "w")
                    {
                        WriteMem(hProcess, Convert.ToInt32(arrStr[1]), Convert.ToInt32(arrStr[2]));
                    }
                    else if (arrStr[0] == "q")
                    {
                        Console.WriteLine("Bye Bye\n", (int)liAddr[0]);
                    }
                }
            }
            else
            {
                Console.WriteLine("App Not Found");
            }
            Console.WriteLine("Press Any Key...");
            Console.ReadKey(true); //Pause
        }
    }
}

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Blogger Templates