首页
社区
课程
招聘
[原创]浅谈视频翻录
发表于: 2024-8-23 23:38 4587

[原创]浅谈视频翻录

2024-8-23 23:38
4587

浅谈视频翻录.md

签名:zZhouQing(未成年)
日期:2024年8月23日

女魔头劝解我好好学习,没事多看题,为看雪网络课程做些贡献,好过无聊蛐蛐。(说我小学生,她才小学生呢,标点符号都打不对)

 于是我对以下样本进行了研究:

  • 大黄蜂视频加密
  • 深造视频加密

 上面俩个软件样本都拥有 Windows 、Android 版本。大黄蜂视频加密 似乎由于经费不足而引起的开发动力不足,更新缓慢,难以对抗市面上的翻录手段。深造视频加密 并没有透露过多的更新内容,与 大黄蜂视频加密 相比,它的防破解强度较高,同时,它的市场份额也更加的大。(盗版的看雪课程均有它份)接下来的内容,从介绍 深造视频加密 开始。

深造视频加密

 软件介绍:

本地视频、在线视频、直播视频加密系统(整套系统永久、全平台、一机一码)
我们承诺随时翻录破解随时全额退款!
我们承诺,翻录一个视频奖励500元,破解一个视频奖励1000元,10万元封顶,支付宝直接转账!!!

 样本版本(Windows):

版本:24.07.524  大小:41.7MB    发布日期:2024年07月05日
(2)、播放器会检测采集卡翻录、软件翻录、破解调试、虚拟机翻录、隐藏进程、AI行为识别翻录、数据分析识别翻录、手机摄像机拍摄翻             录等,请尊重视频著作权!对于恶意破坏者收回权限处理!情节严重,我们会对涉及侵权等违法行为搜集资料并起诉;
(3)、播放过程中不要外接U盘和移动硬盘,不要更换电脑CPU、主板、硬盘、显示器等,否则会导致电脑机器码超限;

 样本版本(Android):

大小:104MB   版本:24.06.111  发布日期:2024年06月29日
(1)、深造播放器是一款逐帧加密的混合式视频加密播放器,用于保护视频版权;需要android 9.0以上系统,或者鸿蒙系统;
(2)、安卓手机要关闭开发者模式、关闭USB调试、播放过程中禁止手机连接电脑;
(3)、安卓播放器禁止:虚拟机录屏、软件录屏、投屏录屏、外接采集卡录屏、root环境、模拟器环境;

 受害人(坛友 hackflame 及网友 战天明):

Android 端分析

Windows 端没意思,考虑到我从未学习过 Android 开发或逆向知识,就从这里开始。

基本原理

 准备如下环境:

  • root 手机
  • mt 管理器
  • GameGuardian
  • 算法助手
  • 浏览器

算法助手配置

 配置如下,需要注意的是,如下配置并无法完全绕过反调试。如感兴趣,请看下去。

 通过 mt 管理器深造播放器 进行解析。

  • com.supermedia.mediaplayer
  • 版本号 58
  • 360加固

 我们知道,程序加壳了,要想 完美逆向 便需要进行 脱壳。但这是 360加固 ,要想将其脱掉,对于 初学者 来说也许得花点时间去学习下 Android 程序加载原理 了。

 在我查看了几篇 安卓逆向文档 后,发现 Android 程序 的运行,一般分为俩层。分别是 java 层,native 层。 java 层的代码是可以进行反编译的,即可以将其还原成源代码查看。

 我迫不及待地去学习新的知识,发现 java 层的代码存储于一个后缀名为 .dex 的文件里。我发现一种内存修改工具,名为 GameGuardian (游戏保护)。可以通过它获取进程内存中的数据。即通过它,获取内存中 .dex 的信息。

DumpDex

 深造播放器 dex 版本:

dex 039
64 65 78 0A 30 33 39 00

dex 035
64 65 78 0A 30 33 35 00

 上面的十六进制数据便是 .dex 文件的特征码。game guardian 附加上 目标进程 ,勾选内存范围 jh (java heap),搜索如上十六进制数据 dump 下来便是 360加固 在运行后解密的 .dex 文件啦。(搜索失败,将内存范围全部勾上后,测试成功,看样子 java 层代码和 java heap 并无关系)

 不过我在事后发现了 dump dex 的脚本,脚本内容如下(可能是我不会用吧,我 dump 失败了,有空重试):

--[[

https://gitee.com/rlyun/dump-dex

]] --local dumpDex = {}function dumpDex:getTargetPackage()
	return gg.getTargetPackage()endfunction dumpDex:getPackageName()
	return self.targetPackageendfunction dumpDex:setPackageName(targetPackage)
	self.targetPackage = targetPackageendfunction dumpDex:getRootDir()
	return string.format('%s/dumpDex', gg.EXT_STORAGE)endfunction dumpDex:getDumpDir()
	return string.format('%s/%s', self:getRootDir(), self:getPackageName())endfunction dumpDex:getRangeMap()
	local rangeMap = self.rangeMap	if rangeMap then
		return rangeMap	end

	rangeMap = {
		Jh = gg.REGION_JAVA_HEAP,
		Ch = gg.REGION_C_HEAP,
		Ca = gg.REGION_C_ALLOC,
		Cd = gg.REGION_C_DATA,
		Cb = gg.REGION_C_BSS,
		PS = gg.REGION_PPSSPP,
		A = gg.REGION_ANONYMOUS,
		J = gg.REGION_JAVA,
		S = gg.REGION_STACK,
		As = gg.REGION_ASHMEM,
		V = gg.REGION_VIDEO,
		O = gg.REGION_OTHER,
		B = gg.REGION_BAD,
		Xa = gg.REGION_CODE_APP,
		Xs = gg.REGION_CODE_SYS	}
	self.rangeMap = rangeMap	return rangeMapendfunction dumpDex:getRangeText()
	local rangeMap = self:getRangeMap()
	local rangeValue = gg.getRanges()
	local ranges = {}

	for k, v in pairs(rangeMap) do
		if (rangeValue & v) == v then
			ranges[#ranges + 1] = k
			rangeValue = rangeValue & ~v		end
	end

	return table.concat(ranges, ' | ')endfunction dumpDex:getRangeNames()
	local map = self:getRangeMap()
	local list = {}
	for k, v in pairs(map) do
		list[#list + 1] = k	end
	return listendfunction dumpDex:selectRange()
	local names = self:getRangeNames()
	local selection = {}
	local rangeMsg = self:getRangeText()

	local curRangName = {}
	for name in string.gmatch(rangeMsg, '%w+') do
		curRangName[name] = true
	end

	for i, name in ipairs(names) do
		selection[i] = (curRangName[name] == true)
	end

	local inputs = gg.multiChoice(names, selection, string.format('当前的选择:%s', rangeMsg))
	if not inputs then
		return
	end

	local map = self:getRangeMap()
	local rangeValue = 0
	for i, v in pairs(inputs) do
		if v then
			local name = names[i]
			rangeValue = rangeValue | map[name]
		end
	end

	gg.setRanges(rangeValue)endfunction dumpDex:stringToHex(s)
	return (string.gsub(s, '.', function(s)
		return string.format('%02x', string.byte(s))
	end))endfunction dumpDex:getDexHeader()
	return 'dex\x0A035\x00'endfunction dumpDex:getResultsStep()
	return #self:getDexHeader()endfunction dumpDex:newDex(address)
	local dex = {}
	setmetatable(dex, {
		__index = self	})

	function dex:getAddress()
		return address	end

	function dex:getName()
		local dexName		local index = self.index		if type(index) ~= 'number' then
			error('需要 dex.index = number', 2)
		end
		if index == 1 then
			dexName = 'classes.dex'
		else
			dexName = string.format('classes%d.dex', index)
		end
		return dexName	end

	function dex:getRangesInfo()
		local rangesInfo = self.rangesInfo		if rangesInfo then
			return rangesInfo		end

		local address = self:getAddress()
		local rangesInfo		local RangesList = gg.getRangesList()
		for _, info in ipairs(RangesList) do
			local startAddr = info.start			local endAddr = info['end']

			-- 找到 dex 在内存中的信息
			if startAddr <= address and address <= endAddr then

				-- 筛选出结束地址最大的唯一信息
				if not rangesInfo or rangesInfo['end'] < info['end'] then
					rangesInfo = info				end
			end
		end

		if not rangesInfo then
			error(string.format('%s没有找到 rangesInfo', self:getName()), 2)
		end

		self.rangesInfo = rangesInfo		return rangesInfo	end

	function dex:getStartAddr()
		return self:getRangesInfo().start	end

	function dex:getEndAddr()
		return self:getRangesInfo()['end']
	end

	function dex:getDexPosition()
		return self:getAddress() - self:getStartAddr()
	end

	function dex:assertProcess()
		local targetPackage = self:getTargetPackage()
		local packageName = self:getPackageName()

		if targetPackage ~= packageName then
			error(string.format('进程发生了改变 %s>%s', packageName, targetPackage), 2)
		end
	end

	function dex:getDumpMemoryPath(startAddr, endAddr, dumpDir, packageName)
		if not packageName then
			packageName = gg.getTargetPackage()
		end
		return string.format('%s/%s-%x-%x.bin', dumpDir, packageName, startAddr, endAddr)
	end

	function dex:dumpMemory(startAddr, endAddr, dumpDir)
		local res = gg.dumpMemory(startAddr, endAddr - 1, dumpDir)
		if res ~= true then
			return false, res		end

		return self:getDumpMemoryPath(startAddr, endAddr, dumpDir, self:getPackageName())
	end

	function dex:dump()
		self:assertProcess()

		local startAddr = self:getStartAddr()
		local endAddr = self:getEndAddr()
		local dumpDir = self:getDumpDir()

		local path, err = self:dumpMemory(startAddr, endAddr, dumpDir)
		if not path then
			error(string.format('无法导出内存\n%s', err), 2)
		end

		return path	end

	function dex:getSize()
		local dexSize = self.dexSize		if dexSize then
			return dexSize		end

		local offset = 32
		local value = {
			address = self:getAddress() + offset,
			flags = gg.TYPE_DWORD		}
		local vlaues = {value}
		vlaues = gg.getValues(vlaues)
		dexSize = vlaues[1].value

		self.dexSize = dexSize		return dexSize	end

	function dex:getDexOutPath()
		return string.format('%s/%s', self:getDumpDir(), self:getName())
	end

	function dex:getDexOutFile(path)
		return assert(io.open(path, 'w'))
	end

	function dex:getDexInputFile(path)
		local f = assert(io.open(path, 'r'))
		f:seek('cur', self:getDexPosition())
		return f	end

	function dex:checkSize()
		-- 正常情况应该 DEX大小是正数,并且小于内存的最大范围
		return dex:getSize() > 0 and dex:getSize() < (dex:getEndAddr() - dex:getStartAddr())
	end

	function dex:out(outPath)
		local binPath = self:dump()
		local inputf = self:getDexInputFile(binPath)
		local dexSize = self:getSize()
		local readSize = 1024 * 1024 * 1
		if dexSize < readSize then
			readSize = dexSize		end

		if not outPath then
			outPath = self:getDexOutPath()
		end
		local outf = self:getDexOutFile(outPath)

		local readLength = 0

		-- 从内存导出的bin文件中提取出 DEX
		local function copy()
			while true do
				local tmp = inputf:read(readSize)
				outf:write(tmp)
				readLength = readLength + readSize				if readLength >= dexSize then
					inputf:close()
					outf:close()
					break
				end
			end
		end

		local ok, err = pcall(copy)

		-- 删除导出的内存文件
		os.remove(binPath)

		if not ok then
			-- 复制 DEX 出错了,删除出错的文件
			os.remove(outPath)
			return false, err		end

		-- 返回导出后的 DEX 文件路径
		return outPath	end

	return dexendfunction dumpDex:results2dexs(results)
	local dexs = {}

	for i = 1, #results, self:getResultsStep() do
		local value = results[i]
		local address = value.address		local dex = self:newDex(address)

		if dex and dex:checkSize() then
			local index = #dexs + 1
			dex.index = index
			dexs[index] = dex		end
	end

	return dexsendfunction dumpDex:getDexs()

	-- 清空当前搜索结果
	gg.clearResults()

	gg.toast('正在搜索DEX文件...')

	-- DEX 文件头
	local dexhead = self:getDexHeader()

	-- h 表示以 HEX (十六进制)的方式搜索,后面跟随需要搜索的十六进制
	local text = 'h ' .. self:stringToHex(dexhead)

	-- 搜索以十六进制格式的 DEX 头信息
	local res = gg.searchNumber(text)
	if res ~= true then
		error(string.format('搜索DEX失败\n%s', res), 2)
	end

	-- 获取全部搜索结果
	local results = gg.getResults(gg.getResultsCount())

	-- 把搜索到的结果解析成 DEX 对象
	local dexs = self:results2dexs(results)

	-- 清空搜索
	gg.clearResults()

	return dexsendfunction dumpDex:getLogPath()
	return string.format('%s/dump.log', self:getDumpDir())endfunction dumpDex:getLogFile()
	return assert(io.open(self:getLogPath(), 'w'))endfunction dumpDex:start()

	local function dumpAll(dexs)
		local log		local ok, err = pcall(function()
			log = self:getLogFile()
		end)

		-- if not ok then
		-- 	if gg.alert(string.format('无法创建LOG文件\n%s', err), '继续', '退出') ~= 1 then
		-- 		return
		-- 	end
		-- end

		local function outLog(msg)
			msg = tostring(msg)

			if log then
				log:write(msg .. '\n')
			end

			if msg:find('%S') then
				gg.toast(msg)
			end
		end

		local msg = string.format('导出包名:%s', self:getTargetPackage())
		outLog(msg)

		local successCount = 0
		local failCount = 0

		for i, dex in ipairs(dexs) do
			local name = dex:getName()
			local msg = string.format('正在导出:%s', name)
			outLog(msg)

			local path, err = dex:out()
			if not path then
				failCount = failCount + 1
				local msg = string.format('导出失败:%s', err)
				outLog(msg)
			else
				successCount = successCount + 1
				local msg = string.format('导出成功:%s', path)
				outLog(msg)

				local msg = string.format('文件大小:%s', dex:getSize())
				outLog(msg)
			end
			outLog('\n')
		end

		local msg = string.format('成功导出 %s 个DEX', successCount)
		if failCount > 0 then
			msg = msg .. '\n' .. string.format('导出失败 %s 个DEX', failCount)
		end
		msg = msg .. '\n' .. string.format('保存路径 %s', self:getDumpDir())

		outLog(msg)

		gg.alert(msg)

		-- 关闭LOG文件
		if log then
			log:close()
		end
	end

	-- 开始计时
	local startTime = os.clock()

	-- 缓存包名,避免进程被切换了导致包名不一致
	self:setPackageName(self:getTargetPackage())

	-- 获取 DEX 对象集
	local dexs = self:getDexs()

	-- 得到解析DEX的耗时时间
	local consuming = os.clock() - startTime	local dexCount = #dexs	local msg = string.format('耗时 %.2fs 在内存中搜索到%d个dex文件', consuming, dexCount)

	local operationNames = {'一键导出全部'}
	local operationFuns = {}
	operationFuns[1] = function()
		return dumpAll(dexs)
	end

	for i, dex in ipairs(dexs) do
		local name = dex:getName()
		local text = name .. '\n' .. dex:getSize() .. '字节'
		local i = #operationNames + 1
		operationNames[i] = text

		operationFuns[i] = function()
			local path, err = dex:out()
			if not path then
				gg.alert(string.format('%s导出失败!\n\n%s', name, err))
				return
			end

			gg.alert(string.format('%s导出成功!\n\n%s', name, path))
		end
	end

	while true do
		if gg.isVisible() then

			local input = gg.choice(operationNames, nil, msg)
			if not input then
				local input2 = gg.alert('您确定要退出吗?', '确定', '最小化')
				if input2 == 1 then
					return
				else
					gg.setVisible(false)
				end

			else
				local func = operationFuns[input]
				self:trySelfCall(func)
			end
		else
			gg.sleep(100)
		end
	endendfunction dumpDex:try(err)
	gg.alert(string.format('try error:\n%s', err))
	return errendfunction dumpDex:trySelfCall(func, ...)
	local ok, err = pcall(func, self, ...)
	if not ok then
		self:try(err)
	endendfunction dumpDex:main()

	local function getMsg()
		local process = string.format('进程:%s', self:getTargetPackage())
		local range = string.format('内存:%s', self:getRangeText())
		local msg = process .. '\n' .. range		return msg	end

	while true do

		if gg.isVisible() then
			local input = gg.choice({'选择内存', '开始导出', '退出程序'}, nil, getMsg())
			if not input then
				gg.setVisible(false)

			elseif input == 1 then
				self:trySelfCall(self.selectRange)

			elseif input == 2 then
				self:trySelfCall(self.start)

			elseif input == 3 then
				return
			end
		else
			gg.sleep(100)
		end
	endenddumpDex:main()

DumpDex所存在的问题

 可以看到,.dex 的属性似乎有些奇怪,它的大小太大了。

 除了大小太大的问题,MT 管理器在解析的时候,也未看到与程序有相关的信息。

验证 DumpDex 的准确性

试探

 回顾下刚才查文档所学的知识点:java 层的代码存储于一个后缀名为 .dex 的文件里。

 设想一下,java 层的代码都存了些什么?(我也不清楚)自然包含程序的界面相关信息吧。

 打开深造播放器,随便输入 Serial,发现下图所示提示:

 返回 GameGuardian 搜索 UTF8:请联系,发现内存属性不是 javaHeap,寻求其他办法。

奇技淫巧

 考虑到能力有限,在万能的互联网上找到了 深造播放器 v1.8.9 最新版本,下载下来。

 apk 基本信息如图所示:

 未加固,这可是个好消息,如图所示常量,皆会在 java heap 中出现。

 实验出真知,发现还是不在 java heap 内存,不过这 Anonymous 内存倒也显特殊。将这块内存导出,最终发现,相关信息其的确存在于 DumpDex 文件中。

SplitDex

 这下子,我敢猜测,这份 .bin 中存在着多份 .dex 文件。(其实我压根没测试,上面的验证是为了开阔下思路,通过老版本验证新版本,好玩吧~ hiahia)

 搜索 .dex 特征码,提取 .bin 中所存在的 .dex,需要注意的是,这份代码所提取的 .dex 文件是不全的,但是正好能覆盖程序主要逻辑。如果需要提取全部 .dex 需要略微变动下代码。

f = open(r"C:\Users\zZhouQing\Documents\MuMu共享文件夹\ShareDex\origin.bin","rb")bytes = f.read()sig = b"\x64\x65\x78\x0a\x30"list = bytes.split(sig)count = 0for v in list:
    path = r"C:\Users\zZhouQing\Documents\MuMu共享文件夹\ShareDex"+"\\"+str(count) + ".dex"
    f = open(path,"wb")
    f.write(sig+v)
    count += 1

反调试 - 第一部分

 查看 io.antiengine 相关代码,这是 深造播放器 防破解的源头之一。(还存在着定时器)

该类含有以下方法:

  • _init
  • info0
  • info1
  • info2
  • isSafe

 为什么方法名要用 info 呢?我猜测,是因为其防破解原理主要是通过 获取系统相关信息 来完成的。

 io.antiengine.info0:

调用 info1
调用 isSafe
获取 pageName list
获取 传感器数量
获取 显示屏数量
获取 Usb 信息
获取 Adb 信息
获取 su 信息
获取 emulator 信息
获取 virtual circumstance

 呵呵,相对于 pdd 等大厂软件获取的系统信息,sz 算是温柔地了。

 发现 info1native 层的函数,我通过查阅文档发现其是 .so export method (so 是 Android 系统下的动态链接库)。

 _init:

str soName = "eagle_sdk";loadLibrary(soName);

 我们将 data/app/.../lib/ 文件夹下的 eagle_sdk.so 提取出来,拖入 ida 中进行反编译。.so 文件是未加壳的,呵呵,看样子 深造视频加密2021 年开始推行的 深造播放器 Android 并没有多安全。

 我觉得 Android 逆向还是挺有意思的,所以用 IDA 过一下 eagle_sdk.so 文件。

 check su:

// su__int64 sub_14CA0(){

  strcpy(v19, "/system/bin/su");
  strcpy(v21, "/product/bin/su");
  strcpy((char *)v22, "$/data/local/bin");
  strcpy(v24, "/system/xbin/su");
  strcpy((char *)v25, "*/system/xbin/which/su");
  strcpy((char *)v26, "$/data/local/xin");
  strcpy((char *)v27, "$/data/local/bin");
  strcpy((char *)v29, "/system/bin/failsafe/su");}

 check magisk and more circumstance:

__int64 sub_151E0(){
  strcpy(v17, "lsposed");
  strcpy(v22, "magisk");
  strcpy(v26, "Magisk");
  strcpy(v28, "/appwidget");
  if ( (unsigned __int8)sub_146E0("/proc/mounts") )
  {
    strcpy((char *)v8 + 1, "/proc/mounts->");
  }
  else if ( (unsigned __int8)sub_146E0("/proc/self/mountstats") )
  {
    strcpy(*(char **)&v8[1], "/proc/self/mountstats->");
  }
  else if ( (unsigned __int8)sub_146E0("/proc/self/mountinfo") )
  {
    strcpy((char *)v8, ",/proc/self/mountinfo->");
  }
  else
  {
    if ( !(unsigned __int8)sub_146E0("/proc/self/maps") )
    strcpy((char *)v8, "\"/proc/self/maps");
  }
 }

 check adb:

__int64 sub_157F0(){
  strcpy(v52, "lsposed");
  strcpy(v57, "magisk");
  strcpy(v61, "Magisk");
  strcpy(&v62[1], "/appwidget");
  strcpy((char *)&dest[1] + 1, "s/");
  strcpy((char *)dest, "$/data/adb/modul");
  if ( !(unsigned __int8)sub_14840(dest, v43) )
  {
    v40 = 0;
    ptr = 0LL;
    v38 = 20;
    strcpy(v39, "/data/adb/");
    v0 = sub_14840(&v38, v43);
    if ( (v38 & 1) != 0 )
      operator delete(ptr);
  }
 }

反反调试

 方法有二,请看下去。

反反调试 - 法一 - 0day

 该漏洞危害很大,直戳 反调试命脉 。不知道各位是否记得 io.eagle_sdk._init 函数?不记得没关系,我会把内容复制下来,方便阅读。

 _init:

str soName = "eagle_sdk";loadLibrary(soName);

 我们直接将 data/app/../lib 中的 eagle_sdk.so 删去,程序是可以正常运行的。此时,深造播放器 Android 便只有 java 层的反调试了,而 java 层的反调试之一(info0、1)早已被我们略过。

反调试 - 第二部分(定时器)

 做 hook 进行反反调试,需要注意 hook 的点位齐全,稍有不慎,可能被封号。程序在登录到主界面后,会开启一个定时器进行反调试。出于本篇随笔的长度考虑,这一部分,交由读者自行实验。

反反调试(防封) - 法二 - hook

 使用算法助手做 hook,经过分析,这个点位既能实现反反调试,又能实现防封。堪称绝佳点位。

截图黑屏

 算法助手开启了这个设置,仍然截图失败。

 猜测原因,第一种可能,算法助手的这个选项是对程序的 java 层代码进行了 hook,而深造播放器的反截图是在 native 层上运行的,故而功能失效。

 猜测原因,第二种可能,算法助手 hook 的点位并不完全。

破解黑屏

 Github 上随便找了个 xposed 插件进行测试,测试结果如下:

 为了保护 看雪论坛 的网络课程,广告我就随便抹去了。

水印

 分为俩种,一种是通过读取内存中的 username 在屏幕中显示,直接 hook 掉相关代码即可。(不能在内存中扫,username 是动态生成的)

 另一种是 bmp 水印,即图片,通过劫持相关网络层包即可,当然,可以在内存中扫一遍,擦除掉。

视频提取

 这部分内容我跟着 xdbg 师傅学习的,和 梁山 beta 一样的难度,需要一个正版号获取对应帧的 key 进行解密。当然,这部分我是懒得写了。

炫技

 小菜之前沉迷逛 飘云阁 论坛,羡慕论坛里大牛们的破解图,这是论坛的文化。在此,我也想炫耀一下。播放器是基于 rust 语言编写的。

Windows端翻录

 HOOK DWM 即可进行录屏,声音的获取需要逆向音频管理器了。(直接获取声音可能会被检测)

HDMI 信号泄露

 通过硬件设备的缺陷进行翻录,基于此,鹏程万里 也难以抵抗。项目的链接放在附录当中了,我本想加入论坛的 翻译小组 ,从事翻译外文的工作,奈何实力不行,只好凭兴趣翻译了。

How does it works? (and how to cite our work or data)You can find a detailed technical explanation of how deep-tempest works in our article. If you found our work or data useful for your research, please consider citing it as follows:@misc{fernández2024deeptempestusingdeeplearning,
      title={Deep-TEMPEST: Using Deep Learning to Eavesdrop on HDMI from its Unintended Electromagnetic Emanations}, 
      author={Santiago Fernández and Emilio Martínez and Gabriel Varela and Pablo Musé and Federico Larroca},
      year={2024},
      eprint={2407.09717},
      archivePrefix={arXiv},
      primaryClass={cs.CR},
      url={https://arxiv.org/abs/2407.09717},
      note={Submitted}}Data

相关法律普及

 根据《中华人民共和国刑法》第二百一十七条,以营利为目的,未经著作权人许可,复制发行、通过信息网络向公众传播其作品的,违法所得数额较大或者有其他严重情节的,处三年以下有期徒刑,并处或者单处罚金。因此,在未经著作权人授权的情况下出售其视频课程,将构成侵权行为。

 在此呼吁大家不要购买盗版课程,共建良好的绿色网络生态环境。

 同时,也希望 深造播放器 的开发者能够注意自己产品中的内容,看雪论坛的课程资源应该是拥有版权保护的,应该吧。。

 虽然我一时半会没话讲,但本人是 尚未成年 的文科生,法律相关知识,迟早会来的。

附录

[都市晚高峰]出售盗版课程获利8000余元 男子因涉嫌侵犯著作权罪被公诉

MT管理器

GameGuardian 101.1

算法助手

Xposed-Disable-FLAG_SECURE

Deep-tempest: Using Deep Learning to Eavesdrop on HDMI from its Unintended Electromagnetic Emanations

TempestSDR.jl

闲话

本文旨在为看雪论坛做出一些贡献,这是我的第一帖,我要学习的东西还有很多很多。如果有错误,我多半也不会改。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2024-8-25 20:31 被zZhouQing编辑 ,原因: 主语用错了。
收藏
免费 8
支持
分享
最新回复 (15)
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2

小菜第一次参加 CTF,险些闯下弥天大祸,在此做个较为正式的道歉。对于 nepnep 小组的师傅们,我感到很抱歉,我犯了错误........(省略六百字)我很抱歉。我想,我该注意下自己品行的修行了。在这俩天,我反复感受所谓的 “包容”,也是第一次体验 CTF 的文化,当看到女魔头(花花)说出 “梁山师傅”的那一刻,似乎误会也该结束了。 睡觉。

最后于 2024-8-24 00:47 被zZhouQing编辑 ,原因:
2024-8-23 23:46
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3

奇怪,我的代码没有高亮。“的地得”还用错了,妈呀,夜晚不适合写随笔。(小菜跑去逛夜场了,坛友千万不要赌博,真的有老千啊,四人桌有三个监控,有专门的软件看)


还有,论坛的网络课程不知道是怎样运营的,如果是单单面向个人,面临的威胁可能有点大。如果可以的话,直接发函。

最后于 2024-8-24 00:02 被zZhouQing编辑 ,原因:
2024-8-23 23:50
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4

哇,感谢认可!虽然我不知道你是谁,但是我觉得咱俩可以一起喝酒,不过似乎没人可以证明谁是第一个。请问,这是什么样的场景问题?


找到你了,老前辈。:)

最后于 2024-8-24 01:09 被zZhouQing编辑 ,原因:
2024-8-24 00:58
0
雪    币: 8
活跃值: (137)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
非常不错的分析文章
2024-8-24 19:40
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
期待楼主分享window与app视频提取的文章
2024-8-24 22:48
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
mb_ldbucrik 期待楼主分享window与app视频提取的文章
没有该打算,本文重心也并非翻录视频,望理解。
2024-8-25 20:34
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
zZhouQing 没有该打算,本文重心也并非翻录视频,望理解。
有什么资料推荐学习不
2024-8-26 18:25
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
9
mb_ldbucrik 有什么资料推荐学习不

我看的文章多数是十年前的了,十年前的帖子文风各有千秋,我很喜欢,和现在报告式的文章有很大的不同。
可以从软件逆向版的最早期开始了解软件逆向。
https://bbs.kanxue.com/forum-4-1181.htm?orderby=lastpid&digest=0


当然,也可以探寻九阴真经与crack之间的关系。(跑江湖)

或者,寻找 ollydbg 的不同写法。(孔乙己)


天涯、明月、刀

https://bbs.kanxue.com/thread-5310.htm


哇哈哈,这些帖子将近 20 年了,看着超有意思。

最后于 2024-8-27 07:23 被zZhouQing编辑 ,原因:
2024-8-27 06:55
0
雪    币: 630
活跃值: (5459)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
反反调试 - 法一 - 0day  这个没看懂什么意思  然后复制的内容是在哪里呢?
2024-8-30 10:00
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
11
梦_魇 反反调试 - 法一 - 0day 这个没看懂什么意思 然后复制的内容是在哪里呢?
应该是我的闲言碎语,看不懂没关系~
2024-8-31 02:14
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
zZhouQing mb_ldbucrik 有什么资料推荐学习不 我看的文章多数是十年前的了,十年前的帖子文风各有千秋,我很喜欢,和现在报告式的文章 ...
没有视频解密或者翻录的资料可以学习吗
2024-8-31 07:45
0
雪    币: 261
活跃值: (547)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
深造播放器难用的一批,早点破解得了
2024-9-1 14:53
0
雪    币: 119
活跃值: (611)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
如何走进windows逆向大门?有推荐路线吗
2024-9-2 02:18
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
15
小柯南 如何走进windows逆向大门?有推荐路线吗

推荐《加密与解密(第四版)》和关注论坛的软件逆向板块,从历史的角度来看,去看以前的贴子,会容易入门些,随着 Windows 逆向的发展,现在的的技术讨论可能很难做到像从前那样谈笑风生。

如果加之个人,我目前关于 Windows 只写过一篇。

https://bbs.kanxue.com/thread-283190.htm

最后于 2024-9-2 02:37 被zZhouQing编辑 ,原因:
2024-9-2 02:35
0
雪    币: 119
活跃值: (611)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
zZhouQing 小柯南 如何走进windows逆向大门?有推荐路线吗 推荐《加密与解密(第四版)》和关注论坛的软件逆向板块,从历史的角度来看,去 ...
感谢,争取看完大部分书的内容
2024-9-2 13:02
0
游客
登录 | 注册 方可回帖
返回
//