天天看點

利用浏覽器擴充和DLL注入俘獲m3u8連結

作者:曹CHG

簡單的情形是這樣的:浏覽器會根據網頁中的視訊标簽或者腳本代碼來找到m3u8連結。網頁中的視訊标簽(<video>)或者腳本代碼(<script>)會指定一個視訊源(src)屬性,這個屬性的值就是m3u8連結或者一個能傳回m3u8連結的位址。例如,一個視訊标簽可能是這樣的: <video src="https://example.com/video.m3u8" controls></video> 這裡的src屬性就是m3u8連結。或者,一個腳本代碼可能是這樣的: <script> var player = new Player("https://example.com/get_m3u8.php?id=123"); player.play(); </script> 這裡的get_m3u8.php是一個能傳回m3u8連結的位址,它根據id參數來動态生成m3u8連結。

然後,浏覽器是通過發送這個連結的HTTP請求,得到一個包含多個.ts視訊片段位址的檔案。浏覽器會按順序請求這些.ts檔案,再用一個播放器來拼接和播放這些視訊片段。但是有些網站會對m3u8連結進行隐藏或者加密,使得無法直接從網頁中找到它。這時候,你可以用開發者工具的網絡頁籤來監視浏覽器發送的所有HTTP請求,看看有沒有包含m3u8的請求。

有沒有不使用浏覽器的網絡螢幕獲得m3u8連結呢?答案是有的,本文将介紹如何通過浏覽器擴充或注入代碼的方法,來擷取m3u8檔案的連結。

具體來說,有以下幾種可能的方法:

通過網絡監視:浏覽器插件可以使用chrome.webRequest API來監聽浏覽器發送或接收的所有HTTP請求,然後過濾出包含m3u8的請求,并擷取其url。這種方法的優點是簡單直接,缺點是可能會影響浏覽器的性能和網絡安全。

通過代碼注入:浏覽器插件可以使用chrome.tabs API或者chrome.extension API來向目标網頁注入一段JavaScript代碼,這段代碼可以擷取網頁中的視訊标簽或者腳本代碼,并從中提取出m3u8 url。這種方法的優點是可以更靈活地适應不同的網頁結構,缺點是可能會破壞網頁的正常功能或者與其他插件沖突。

通過開發者工具:浏覽器插件可以使用chrome.devtools API來擴充浏覽器的開發者工具,添加一個專門用于擷取m3u8 url的面闆或者按鈕。這種方法的優點是可以讓使用者更友善地操作,缺點是需要使用者主動打開開發者工具并選擇相應的功能。

網絡監視:使用WinPcap或者Npcap等庫來捕獲網絡資料包,然後過濾出包含m3u8的請求,并擷取其url。以下是一個使用C#和SharpPcap庫的示例代碼:

using System;

using System.Text.RegularExpressions;

using SharpPcap;

using PacketDotNet;

namespace M3U8Sniffer

{

class Program

{

static void Main(string[] args)

{

// Get the list of available devices

var devices = CaptureDeviceList.Instance;

// Check if any device exists

if (devices.Count < 1)

{

Console.WriteLine("No device found.");

return;

}

// Print the list of devices

Console.WriteLine("The following devices are available:");

for (int i = 0; i < devices.Count; i++)

{

Console.WriteLine("{0}) {1}", i, devices[i].Description);

}

// Ask the user to choose a device

Console.WriteLine("Enter the device number (0-{0}):", devices.Count - 1);

int deviceIndex = int.Parse(Console.ReadLine());

// Get the chosen device

var device = devices[deviceIndex];

// Open the device with default configuration

device.Open();

// Set a filter to capture only HTTP requests

device.Filter = "tcp port 80";

// Register a handler for packet arrival event

device.OnPacketArrival += new PacketArrivalEventHandler(OnPacketArrival);

// Start capturing packets

Console.WriteLine("Start capturing on {0}", device.Description);

device.StartCapture();

// Wait for 'Enter' from the user.

Console.WriteLine("Press Enter to stop...");

Console.ReadLine();

// Stop capturing packets

device.StopCapture();

// Close the device

device.Close();

}

// The handler for packet arrival event

private static void OnPacketArrival(object sender, CaptureEventArgs e)

{

// Parse the packet as TCP packet

var packet = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);

var tcpPacket = packet.Extract<TcpPacket>();

// Check if the TCP packet contains payload

if (tcpPacket != null && tcpPacket.PayloadData != null)

{

// Convert the payload data to string

var data = System.Text.Encoding.UTF8.GetString(tcpPacket.PayloadData);

// Check if the data is an HTTP request

if (data.StartsWith("GET") || data.StartsWith("POST"))

{

// Extract the request URI from the data

var lines = data.Split('\n');

var uri = lines[0].Split(' ')[1];

// Check if the URI contains m3u8

if (uri.Contains("m3u8"))

{

// Print the m3u8 url to the console

Console.WriteLine("Found m3u8 url: {0}", uri);

}

}

}

}

}

}

代碼注入(js代碼注入):使用chrome.tabs API或者chrome.extension API來向目标網頁注入一段JavaScript代碼,這段代碼可以擷取網頁中的視訊标簽或者腳本代碼,并從中提取出m3u8 url。以下是一個使用JavaScript和chrome.tabs API的示例代碼:

// Get the current active tab in the current window

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {

// Get the first tab object in the array

var tab = tabs[0];

// Inject a content script into the tab

chrome.tabs.executeScript(tab.id, {

code: `

// Get all the video elements in the document

var videos = document.getElementsByTagName('video');

// Loop through each video element

for (var i = 0; i < videos.length; i++) {

// Get the video source attribute or source child element

var src = videos[i].src || videos[i].querySelector('source').src;

// Check if the source contains m3u8

if (src.includes('m3u8')) {

// Send the m3u8 url to the background script

chrome.runtime.sendMessage({url: src});

}

}

// Get all the script elements in the document

var scripts = document.getElementsByTagName('script');

// Create a regular expression to match m3u8 url

var regex = /https?:\/\/\S+\.m3u8\b/g;

// Loop through each script element

for (var i = 0; i < scripts.length; i++) {

// Get the script text content

var text = scripts[i].textContent;

// Check if the text matches the regex

var match = regex.exec(text);

if (match) {

// Send the m3u8 url to the background script

chrome.runtime.sendMessage({url: match[0]});

}

}

`

});

});

// Listen for messages from the content script

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {

// Check if the message contains a url

if (message.url) {

// Print the m3u8 url to the console

console.log("Found m3u8 url: " + message.url);

}

});

代碼注入(dll代碼注入):使用DLL注入等技術來修改目标程序的記憶體,然後執行一段代碼來擷取m3u8 url。以下是一個使用C++和Windows API的示例代碼:

#include <windows.h>

#include <tlhelp32.h>

#include <iostream>

// A function to get the process id by name

DWORD GetProcessIdByName(const char* name)

{

// Create a snapshot of all processes

HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

// Check if the snapshot is valid

if (snapshot != INVALID_HANDLE_VALUE)

{

// Initialize a PROCESSENTRY32 structure

PROCESSENTRY32 entry;

entry.dwSize = sizeof(PROCESSENTRY32);

// Get the first process in the snapshot

if (Process32First(snapshot, &entry))

{

// Loop through all processes in the snapshot

do

{

// Compare the process name with the given name

if (strcmp(entry.szExeFile, name) == 0)

{

// Return the process id

return entry.th32ProcessID;

}

} while (Process32Next(snapshot, &entry));

}

}

// Return 0 if not found or failed

return 0;

}

// A function to inject a DLL into a process by id

BOOL InjectDll(DWORD pid, const char* dllPath)

{

// Open the target process with all access

HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

// Check if the process handle is valid

if (process != NULL)

{

// Get the address of LoadLibraryA function in kernel32.dll module

LPVOID loadLibraryAddr = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");

// Check if the address is valid

if (loadLibraryAddr != NULL)

{

// Allocate memory in the target process for the DLL path

LPVOID dllPathAddr = VirtualAllocEx(process, NULL, strlen(dllPath) + 1, MEM_COMMIT, PAGE_READWRITE);

// Check if the memory allocation is successful

if (dllPathAddr != NULL)

{

// Write the DLL path to the allocated memory

BOOL writeResult = WriteProcessMemory(process, dllPathAddr, dllPath, strlen(dllPath) + 1, NULL);

// Check if the write operation is successful

if (writeResult)

{

// Create a remote thread in the target process to execute LoadLibraryA with DLL path as argument

HANDLE thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibraryAddr, dllPathAddr, 0, NULL);

// Check if the thread handle is valid

if (thread != NULL)

{

// Wait for the thread to finish

WaitForSingleObject(thread, INFINITE);

// Close the thread handle

CloseHandle(thread);

// Free the allocated memory in the target process

VirtualFreeEx(process, dllPathAddr, 0, MEM_RELEASE);

// Close the process handle

CloseHandle(process);

// Return true as success

return true;

}

}

// Free the allocated memory in the target process

VirtualFreeEx(process, dllPathAddr, 0, MEM_RELEASE);

}

}

// Close the process handle

CloseHandle(process);

}

開發者工具的代碼:使用chrome.devtools API來擴充浏覽器的開發者工具,添加一個專門用于擷取m3u8 url的面闆或者按鈕。以下是一個使用JavaScript和chrome.devtools API的示例代碼:

// Define a panel in the devtools

chrome.devtools.panels.create("M3U8 Sniffer", "icon.png", "panel.html", function(panel) {

// Register a callback for panel shown event

panel.onShown.addListener(function(window) {

// Get the current inspected tab id

var tabId = chrome.devtools.inspectedWindow.tabId;

// Send a message to the background script to start capturing packets

chrome.runtime.sendMessage({action: "start", tabId: tabId});

// Listen for messages from the background script

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {

// Check if the message contains a url and matches the tab id

if (message.url && message.tabId == tabId) {

// Append the m3u8 url to the panel window

window.document.body.innerHTML += "<p>" + message.url + "</p>";

}

});

});

// Register a callback for panel hidden event

panel.onHidden.addListener(function(window) {

// Get the current inspected tab id

var tabId = chrome.devtools.inspectedWindow.tabId;

// Send a message to the background script to stop capturing packets

chrome.runtime.sendMessage({action: "stop", tabId: tabId});

});

});

這些代碼編譯後,如何安裝到浏覽器中呢?請對4種方法分别說明一下安裝過程:

網絡監視:這種方法需要編譯成一個可執行檔案,然後運作在背景,不需要安裝到浏覽器中。但是需要使用者自己啟動和關閉程式,并且可能需要管理者權限。

代碼注入(js代碼注入):這種方法需要編譯成一個浏覽器擴充,然後在浏覽器的擴充管理頁面進行安裝。具體的步驟可以參考這個連結:https://developer.chrome.com/docs/extensions/mv3/getstarted/

代碼注入(dll代碼注入):這種方法需要編譯成一個DLL檔案,然後使用一些工具或者程式來将其注入到目标程序中。具體的步驟可以參考這個連結:https://www.codeproject.com/Articles/2082/API-hooking-revealed

開發者工具:這種方法也需要編譯成一個浏覽器擴充,然後在浏覽器的擴充管理頁面進行安裝。具體的步驟可以參考這個連結:https://developer.chrome.com/docs/extensions/mv3/devtools/

如果要問哪種方法最友善最安全?

這個問題的答案可能比較主觀,不同的人可能有不同的看法。我的看法是:

我覺得開發者工具的方法最友善最安全,因為它隻需要安裝一個浏覽器擴充,然後在需要的時候打開開發者工具就可以使用。它不會影響浏覽器的性能和安全,也不會修改目标程序的記憶體。

我覺得代碼注入(js代碼注入)的方法最友善最安全,因為它可以适應不同的網頁結構,而且隻需要注入一段JavaScript代碼,不會對目标程序造成太大的影響。它也隻需要安裝一個浏覽器擴充,而且可以自動運作。

我覺得網絡監視的方法最友善最安全,因為它可以捕獲所有的HTTP請求,而不需要關心網頁的具體内容。它也不需要安裝任何浏覽器擴充,隻需要運作一個可執行檔案就可以了。它也不會修改目标程序的記憶體,隻是讀取網絡資料包。

我覺得代碼注入(dll代碼注入)的方法最友善最安全,因為它可以直接在目标程序中執行任意代碼,而不受浏覽器的限制。它也不需要安裝任何浏覽器擴充,隻需要使用一些工具或者程式就可以了。它也可以實作更多的功能,而不隻是擷取m3u8連結。

什麼是浏覽器擴充?

浏覽器擴充是一種可以增強浏覽器功能和使用者體驗的軟體元件。它們可以在浏覽器中運作一些代碼,通路一些API,修改一些網頁内容,或者提供一些額外的界面和功能。舉例如下:

可以增強浏覽器的曆史記錄功能,讓使用者可以按照日期檢視浏覽過的網頁1

可以增強浏覽器的拼寫和文法檢查功能,讓使用者在寫作時可以自動糾正錯誤2

可以增強浏覽器的截圖和标注功能,讓使用者可以友善地截取和編輯網頁内容1

可以增強浏覽器的閱讀體驗,讓使用者可以在一個幹淨和沉浸式的界面中閱讀網頁内容3

可以增強浏覽器的安全性和隐私性,讓使用者可以攔截廣告和惡意網站,或者使用 VPN 代理來保護自己的網絡活動1

浏覽器擴充可以通路一些特定的 API,來實作一些特殊的功能。以下是一些例子:

可以通路 chrome.devtools API 來擴充浏覽器的開發者工具,添加一些專門用于擷取 m3u8 url 的面闆或者按鈕4

可以通路 chrome.tabs API 來管理浏覽器的标簽頁,實作一些暫存和恢複标簽頁的功能

可以通路 chrome.storage API 來存儲和同步擴充的資料,實作一些書簽和筆記的功能

可以通路 chrome.webRequest API 來監視和修改網絡請求,實作一些網絡分析和過濾的功能

浏覽器擴充可以提供額外的界面和功能,來增加使用者的便利性和趣味性。以下是一些例子:

可以提供一個新标簽頁,來展示一些美麗的背景圖檔和詩詞

可以提供一個側邊欄,來顯示一些實用的工具和資訊

可以提供一個懸浮視窗,來顯示一些翻譯或者定義

可以提供一個遊戲界面,來讓使用者在新标簽頁中玩一些小遊戲

浏覽器擴充可以修改網頁内容,來實作一些個性化或者優化的目的。以下是一些例子:

可以修改網頁的字型或者顔色,來适應使用者的喜好或者視力需求

可以修改網頁的布局或者樣式,來适應使用者的螢幕大小或者裝置類型

可以修改網頁的内容或者元素,來去除一些不需要或者幹擾的部分

可以修改網頁的腳本或者事件,來增加一些互動或者動畫效果

如何開發浏覽器擴充?

要開發一個浏覽器擴充,通常需要以下幾個步驟:

首先,你需要建立一個 manifest.json 檔案,來聲明你的擴充的基本資訊,如名稱,版本,描述,圖示,權限等12。

然後,你需要建立一些 JavaScript 檔案,來定義你的擴充的功能和邏輯。你可以使用一些特定的 API,來與浏覽器或者網頁進行互動123。

接着,你需要建立一些 HTML 和 CSS 檔案,來定義你的擴充的使用者界面和樣式。你可以使用一些特定的元素,來建立彈出視窗,選項頁面,内容腳本等124。

最後,你需要在浏覽器中加載和測試你的擴充。你可以在浏覽器的擴充管理頁面中啟用開發者模式,然後選擇你的擴充所在的檔案夾34。你可以在浏覽器中檢視你的擴充的效果和錯誤資訊。

具體步驟如下:

建立一個 manifest.json 檔案,來聲明我們的擴充的基本資訊,如名稱,版本,描述,圖示,權限等。例如:

{

"manifest_version": 2,

"name": "M3U8 Finder",

"version": "1.0",

"description": "A simple extension that finds all m3u8 links in the current web page.",

"browser_action": {

"default_icon": "icon.png",

"default_popup": "popup.html"

},

"permissions": [

"tabs"

]

}

然後,我們需要建立一個 icon.png 檔案,來作為我們的擴充的圖示。這個檔案可以是任意的圖檔檔案,但是最好是 16x16 或者 32x32 的尺寸。例如:

![icon.png](data:image/png;base64,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

接着,我需要建立一個 popup.html 檔案,來定義我的擴充的彈出視窗的使用者界面和樣式。這個檔案可以包含任意的 HTML 和 CSS 代碼,但是最好是簡單和清晰的。例如:

<html>

<head>

<style>

body {

font-family: Arial, sans-serif;

font-size: 16px;

color: white;

background-color: black;

margin: 0;

padding: 10px;

}

#time {

font-weight: bold;

font-size: 24px;

}

</style>

</head>

<body>

<div id="time"></div>

<script src="popup.js"></script>

</body>

</html>

最後,我需要建立一個 popup.js 檔案,來定義我的擴充的功能和邏輯。這個檔案可以使用任意的 JavaScript 代碼,但是最好是遵循浏覽器擴充的 API 和規範。例如:

// 擷取顯示時間的元素

var timeElement = document.getElementById("time");

// 定義一個函數,用來格式化時間

function formatTime(date) {

var hours = date.getHours();

var minutes = date.getMinutes();

var seconds = date.getSeconds();

// 補零

if (hours < 10) {

hours = "0" + hours;

}

if (minutes < 10) {

minutes = "0" + minutes;

}

if (seconds < 10) {

seconds = "0" + seconds;

}

// 傳回格式化後的時間字元串

return hours + ":" + minutes + ":" + seconds;

}

// 定義一個函數,用來更新時間

function updateTime() {

// 擷取目前時間

var now = new Date();

// 格式化時間

var timeString = formatTime(now);

// 顯示時間

timeElement.textContent = timeString;

}

// 調用一次更新時間函數,以顯示初始時間

updateTime();

// 設定一個定時器,每隔一秒更新一次時間

setInterval(updateTime, 1000);

以上就是一個簡單的浏覽器擴充的例子。你可以把這些檔案放在同一個檔案夾裡,然後在浏覽器中加載和測試它。