找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
楼主: eldenring

[数值计算] bat如何计算出文件的eD2k_HASH(仿照LinkCreator0.7)

[复制链接]
发表于 2025-6-16 09:38:31 | 显示全部楼层
回复 15# 娃娃


    ed2k的文件hash片段是用MD4的 ,可以用自带的certutil进行 ,自己改下就行
发表于 2025-6-16 10:30:41 | 显示全部楼层
回复  娃娃


    ed2k的文件hash片段是用MD4的 ,可以用自带的certutil进行 ,自己改下就行
Five66 发表于 2025-6-16 09:38




谢谢!之前AI给出的说法是自带的certutil不支持文件hash片段MD4。

测试certutil -hashfile计算出的是文件MD4,非是先分割,再整合后(ed2k)文件MD4。


自己生搬硬套@xp3000君的还是不成!



原打算假以时日发帖请教不依赖第三方工具实现的方法。想说先观望下这段期间有没有朋友帮忙补一个ed2k_hash.exe便携式命令行程式,自己现在是没检索到。


@Five66君何以教我?可以实现的话,娃娃立刻!马上!赶紧去发新帖。


若是不依赖第三方工具,cmd+js+PowerShell最好啦。

发表于 2025-6-16 21:54:44 | 显示全部楼层
回复 17# 娃娃


    把整个文件当成一个片段就行了 ,大大大部分的ed2k都这样
下面是弄出当前目录下所有png的ed2k示例

  1. @set @do_not_save_as_utf8=1;/*&echo off

  2. for %%a in (*.png) do (
  3. set "_name=%%~nxa"
  4. set "_size=%%~za"
  5. set "_md4="
  6. for /f "skip=1 delims=" %%b in ('certutil -hashfile "%%a" MD4') do (
  7. if not defined _md4 set _md4=%%b
  8. )
  9. setlocal enabledelayedexpansion
  10. set _name=!_name:%%=%%25!
  11. set _name=!_name: =%%20!
  12. set _md4=!_md4: =!
  13. echo ed2k://^|file^|!_name!^|!_size!^|!_md4!^|/
  14. echo,
  15. endlocal
  16. )

  17. echo done&pause&exit /b 0 */
复制代码
发表于 2025-6-16 23:33:23 | 显示全部楼层
本帖最后由 aloha20200628 于 2025-6-17 00:06 编辑

回复 17# 娃娃

以下从网上习得,仅供参考...
一。
    ... 文件类型的 eD2k 链接形如:
    <文件名> (0 Bytes)
其中获取 '文件Hash' 的算法其实是MD4算法的一种变体,即把文件数据分成n个长度=9728000字节(相当于9500KB或约9.28MB)的等长数据块和最后剩余的一个不等长数据块,对每个数据块都要计算其MD4哈希值,如果文件长度正好是9500KB的整倍数,就会剩余一个长度为0的数据块作为结尾,将所有这些数据块的MD4哈希值按顺序连接,再计算其MD4哈希值,方可获取该文件完整的eD2k哈希值。仅当一个文件长度小于9500KB的文件eD2k哈希值才与该文件的MD4哈希值完全相同 ...

二。
    ... The Algorithm roughly works as follows:
    The data is split into 9500 KiB chunks, where the last one can be smaller.
    Each chunk is hashed with the MD4 algorithm.
    If the file is smaller than a single chunk, the result is the hash of the first chunk.
    Otherwise, the result is the MD4 hash of all concatenated chunk hashes....
发表于 2025-6-17 12:17:07 | 显示全部楼层
本帖最后由 aloha20200628 于 2025-6-17 12:29 编辑

回复 15# 娃娃

从网址 http://prdownloads.sourceforge.n ... _setup.exe?download 下载的 ed2k_hash_0.4.0_setup.exe,可先随便安装到一个子目录中,其中有一个命令行运行程序是 ed2k_hash.exe,其大小约 36.1KB,此程序可以直接复制到其他电脑上即可正常使用(不必再重复原安装过程),如在其所在目录中运行

  1. ed2k_hash "abc.txt" >"文件_ed2k.txt"
复制代码
即可将文件 abc.txt 的 ed2k 链址写入 文件_ed2k.txt,亦可将指定目录 d:\xyz\123 中所有文件的 ed2k 链址写入 "目录_ed2k.txt",如下代码运行

  1. ed2k_hash "d:\xyz\123" >"目录_ed2k.txt"
复制代码
若采用参数 -r 则可递归处理每个子目录

  1. ed2k_hash -r "d:\xyz\123" >"全目录_ed2k.txt"
复制代码
发表于 2025-6-17 19:52:03 | 显示全部楼层
回复 18# Five66

测试无法秒。前辈再研究研究,结合js或可解决。不依赖第三方若能成是值得期待的。
发表于 2025-6-17 19:58:50 | 显示全部楼层
回复 20# aloha20200628


   琢磨怎么不安装ed2k_hash_0.4.0_setup.exe的情况下提取到命令行程式感觉自己已经无可救药了。
发表于 2025-6-17 20:02:42 | 显示全部楼层
回复 19# aloha20200628

是啊,现在只得寄望于Java与PowerShell能解决分割,整合的问题。
发表于 2025-6-17 20:26:26 | 显示全部楼层
回复 21# 娃娃


    啊 ,无法秒 ,看来不是用的emule客户端 ,这样的话ed2k只能规规矩矩的弄
jscript不带md4 ,需要自行实现 ,虽然md4的实现能够抄网上的代码 ,但是二进制读取慢 ,100多k读取都要几秒 ,hash时间非常非常非常慢的
powershell貌似也不带md4 ,而且有点坑 ,略过
这样一来就剩下C#了 ,可以自动用系统自带的c#编译器编译运行 ,试试网上搜索对应代码
发表于 2025-6-17 21:15:29 | 显示全部楼层
本帖最后由 娃娃 于 2025-6-17 21:18 编辑

回复 24# Five66

谢谢分析科普!
那……
ed2k_hash.exe实在找不到!
不知能调用诸如LinkCreator.exe,HashCalculator.exe(不是命令行程式)实现批处理吗?
发表于 2025-6-17 23:14:27 | 显示全部楼层
本帖最后由 Five66 于 2025-6-18 23:06 编辑

回复 25# 娃娃


    弄了个c#的 ,将下面的保存为ansi编码的bat运行
没有cs_ed2k_hash.exe的话自动尝试编译 ,有cs_ed2k_hash.exe的话直接运行
运行后没问题的话会计算当前目录下所有文件的ed2k (不包括子目录)
原本的有问题 ,已修改

  1. /* 2>nul&cls&@echo off
  2. set "exename=cs_ed2k_hash.exe"&setlocal
  3. if not exist "%exename%" echo 未找到%exename%&call :bianyi
  4. if not exist "%exename%" echo 需要%exename%,将退出&echo,&pause&exit /b
  5. echo,&endlocal

  6. set _self=%%~nx0
  7. for %%a in (*) do (
  8. set "_name=%%~nxa"
  9. set "_size=%%~za"
  10. if "%%~nxa" neq "%_self%" (
  11. if "%%~nxa" neq "%exename%" (
  12. for /f "delims=" %%b in ('%exename% "%%a"') do set _md4=%%b
  13. setlocal enabledelayedexpansion
  14. if "!_size!" neq "0" (
  15. set _name=!_name:%%=%%25!
  16. set _name=!_name: =%%20!
  17. set _md4=!_md4: =!
  18. echo ed2k://^|file^|!_name!^|!_size!^|!_md4!^|/
  19. echo,&endlocal
  20. ))))

  21. echo done&pause&exit /b 0

  22. :bianyi
  23. echo 开始尝试编译
  24. for /f "delims=" %%a in ('dir /b /ad /o-n "%systemroot%\Microsoft.NET"') do (
  25. for /f "delims=" %%b in ('dir /b /ad /o-n "%systemroot%\Microsoft.NET\%%a"') do (
  26. for /f "delims=" %%r in ('dir /b /a-d "%systemroot%\Microsoft.NET\%%a\%%b\csc.exe"') do (
  27. if "%%r"=="csc.exe" (
  28. set "csc=%systemroot%\Microsoft.NET\%%a\%%b\csc.exe"
  29. echo,已找到C#编译器,开始编译&echo,&goto :aaa)
  30. )))
  31. echo 找不到C#编译器csc.exe&exit/b
  32. :aaa
  33. "%csc%"  /target:exe /out:"%exename%"  "%~f0"
  34. echo,&timeout /t 1 1>nul
  35. if exist "%exename%" (echo,编译成功,将运行) else (echo,编译失败)
  36. exit/b
  37. */

  38. using System;
  39. using System.Text;

  40. namespace zxcvbnm{class Program{static void Main(string[] args){
  41. if(0==args.Length||!System.IO.File.Exists(args[0]))return;
  42. System.IO.FileStream f=System.IO.File.OpenRead(args[0]);
  43. if(0==f.Length){f.Close();return;}
  44. int md4_block=9500*1024;
  45. byte[] md4_nil=new byte[]{49,214,207,224,209,106,233,49,183,60,89,215,224,192,137,192};
  46. byte[] bf1=new byte[md4_block],bf2,bf3;
  47. Blood.COM.Security.MD4 md4=new Blood.COM.Security.MD4();
  48. System.IO.MemoryStream m=new System.IO.MemoryStream();
  49. int aaa=0,i=0;
  50. if((f.Length>0)&&(f.Length<md4_block)){
  51. bf3=new byte[f.Length];f.Read(bf3,0,bf3.Length);
  52. System.Console.WriteLine(md4.GetHexHashFromBytes(bf3));
  53. }else{
  54. while(true){
  55. aaa=f.Read(bf1,0,md4_block);
  56. if(0==aaa){if(0==(f.Length%md4_block))m.Write(md4_nil,0,16);
  57. break;
  58. }
  59. if(md4_block==aaa){
  60. bf2=md4.GetByteHashFromBytes(bf1);
  61. }else{
  62. bf3=new byte[aaa];
  63. for(;i<aaa;i++)bf3[i]=bf1[i];
  64. bf2=md4.GetByteHashFromBytes(bf3);
  65. }
  66. m.Write(bf2,0,bf2.Length);
  67. }
  68. m.Capacity=(int)m.Length;//.Capacity return int ,.Length return long ,WTF
  69. System.Console.WriteLine(md4.GetHexHashFromBytes(m.GetBuffer()));
  70. }
  71. f.Close();m.Close();}}}

  72. /*
  73. Copyright 2002 Blood (eaststarbuy@sina.com)
  74. This code is ported from Norbert Hranitzky's
  75. (norbert.hranitzky@mchp.siemens.de)
  76. Java version.
  77. */
  78. //reference Namespace
  79. namespace Blood.COM.Security{
  80. public class MD4{
  81. // MD4 specific object variables
  82. private const int BLOCK_LENGTH = 64;        // = 512 / 8
  83. private uint[] context = new uint[4];
  84. private long count;
  85. private byte[] buffer = new byte[BLOCK_LENGTH];
  86. private uint[] X = new uint[16];
  87. // Constructors
  88. public MD4(){
  89. engineReset();
  90. }

  91. private MD4(MD4 md): this(){
  92. //this();
  93. context = (uint[])md.context.Clone();
  94. buffer = (byte[])md.buffer.Clone();
  95. count = md.count;
  96. }
  97. // Clonable method implementation
  98. public object Clone(){
  99. return new MD4(this);
  100. }
  101. // JCE methods
  102. private void engineReset(){
  103. // initial values of MD4 i.e. A, B, C, D
  104. // as per rfc-1320; they are low-order byte first
  105. context[0] = 0x67452301;
  106. context[1] = 0xEFCDAB89;
  107. context[2] = 0x98BADCFE;
  108. context[3] = 0x10325476;
  109. count = 0L;
  110. for(int i = 0; i < BLOCK_LENGTH; i++){
  111. buffer[i] = 0;
  112. }
  113. }

  114. private void engineUpdate(byte b){
  115. // compute number of bytes still unhashed; ie. present in buffer
  116. int i = (int)(count % BLOCK_LENGTH);
  117. count++;            // update number of bytes
  118. buffer[i] = b;
  119. if(i == BLOCK_LENGTH - 1)
  120. transform(ref buffer, 0);
  121. }

  122. private void engineUpdate(byte[] input, int offset, int len){
  123. // make sure we don't exceed input's allocated size/length
  124. if(offset < 0 || len < 0 || (long)offset + len > input.Length){
  125. throw new ArgumentOutOfRangeException();
  126. }
  127. // compute number of bytes still unhashed; ie. present in buffer
  128. int bufferNdx = (int)(count % BLOCK_LENGTH);
  129. count += len;        // update number of bytes
  130. int partLen = BLOCK_LENGTH - bufferNdx;
  131. int i = 0;
  132. if(len >= partLen){
  133. Array.Copy(input, offset + i, buffer, bufferNdx, partLen);
  134. transform(ref buffer, 0);
  135. for(i = partLen; i + BLOCK_LENGTH - 1 < len; i+= BLOCK_LENGTH){
  136. transform(ref input, offset + i);
  137. }
  138. bufferNdx = 0;
  139. }
  140. // buffer remaining input
  141. if(i < len){
  142. Array.Copy(input, offset + i, buffer, bufferNdx, len - i);
  143. }
  144. }

  145. private byte[] engineDigest(){
  146. // pad output to 56 mod 64; as RFC1320 puts it: congruent to 448 mod 512
  147. int bufferNdx = (int)(count % BLOCK_LENGTH);
  148. int padLen = (bufferNdx < 56) ? (56 - bufferNdx) : (120 - bufferNdx);
  149. // padding is always binary 1 followed by binary 0's
  150. byte[] tail = new byte[padLen + 8];
  151. tail[0] = (byte)0x80;
  152. // append length before final transform
  153. // save number of bits, casting the long to an array of 8 bytes
  154. // save low-order byte first.
  155. for(int i = 0; i < 8 ; i++){
  156. tail[padLen + i] = (byte)((count * 8) >> (8 * i));
  157. }
  158. engineUpdate(tail, 0, tail.Length);
  159. byte[] result = new byte[16];
  160. // cast this MD4's context (array of 4 uints) into an array of 16 bytes.
  161. for(int i = 0;i < 4; i++){
  162. for(int j = 0; j < 4; j++){
  163. result[i * 4 + j] = (byte)(context[i] >> (8 * j));
  164. }}
  165. // reset the engine
  166. engineReset();
  167. return result;
  168. }

  169. public byte[] GetByteHashFromBytes(byte[] b){
  170. MD4 md4 = new MD4();
  171. md4.engineUpdate(b, 0, b.Length);
  172. return md4.engineDigest();
  173. }

  174. public string GetHexHashFromBytes(byte[] b){
  175. byte[] e = GetByteHashFromBytes(b);
  176. return bytesToHex(e, e.Length);
  177. }

  178. private static string bytesToHex(byte[] a, int len){
  179. string temp = BitConverter.ToString(a);
  180. // We need to remove the dashes that come from the BitConverter
  181. StringBuilder sb = new StringBuilder((len - 2) / 2);    // This should be the final size
  182. for(int i = 0; i < temp.Length ; i++){
  183. if(temp[i] != '-'){
  184. sb.Append(temp[i]);
  185. }}
  186. return sb.ToString();
  187. }

  188. // own methods
  189. private void transform(ref byte[] block, int offset){
  190. // decodes 64 bytes from input block into an array of 16 32-bit
  191. // entities. Use A as a temp var.
  192. for (int i = 0; i < 16; i++){
  193. X[i] = ((uint)block[offset++] & 0xFF)     |
  194. (((uint)block[offset++] & 0xFF) <<  8)   |
  195. (((uint)block[offset++] & 0xFF) <<  16)  |
  196. (((uint)block[offset++] & 0xFF) <<  24);
  197. }
  198. uint A = context[0];
  199. uint B = context[1];
  200. uint C = context[2];
  201. uint D = context[3];
  202. A = FF(A, B, C, D, X[ 0],  3);
  203. D = FF(D, A, B, C, X[ 1],  7);
  204. C = FF(C, D, A, B, X[ 2], 11);
  205. B = FF(B, C, D, A, X[ 3], 19);
  206. A = FF(A, B, C, D, X[ 4],  3);
  207. D = FF(D, A, B, C, X[ 5],  7);
  208. C = FF(C, D, A, B, X[ 6], 11);
  209. B = FF(B, C, D, A, X[ 7], 19);
  210. A = FF(A, B, C, D, X[ 8],  3);
  211. D = FF(D, A, B, C, X[ 9],  7);
  212. C = FF(C, D, A, B, X[10], 11);
  213. B = FF(B, C, D, A, X[11], 19);
  214. A = FF(A, B, C, D, X[12],  3);
  215. D = FF(D, A, B, C, X[13],  7);
  216. C = FF(C, D, A, B, X[14], 11);
  217. B = FF(B, C, D, A, X[15], 19);
  218. A = GG(A, B, C, D, X[ 0],  3);
  219. D = GG(D, A, B, C, X[ 4],  5);
  220. C = GG(C, D, A, B, X[ 8],  9);
  221. B = GG(B, C, D, A, X[12], 13);
  222. A = GG(A, B, C, D, X[ 1],  3);
  223. D = GG(D, A, B, C, X[ 5],  5);
  224. C = GG(C, D, A, B, X[ 9],  9);
  225. B = GG(B, C, D, A, X[13], 13);
  226. A = GG(A, B, C, D, X[ 2],  3);
  227. D = GG(D, A, B, C, X[ 6],  5);
  228. C = GG(C, D, A, B, X[10],  9);
  229. B = GG(B, C, D, A, X[14], 13);
  230. A = GG(A, B, C, D, X[ 3],  3);
  231. D = GG(D, A, B, C, X[ 7],  5);
  232. C = GG(C, D, A, B, X[11],  9);
  233. B = GG(B, C, D, A, X[15], 13);
  234. A = HH(A, B, C, D, X[ 0],  3);
  235. D = HH(D, A, B, C, X[ 8],  9);
  236. C = HH(C, D, A, B, X[ 4], 11);
  237. B = HH(B, C, D, A, X[12], 15);
  238. A = HH(A, B, C, D, X[ 2],  3);
  239. D = HH(D, A, B, C, X[10],  9);
  240. C = HH(C, D, A, B, X[ 6], 11);
  241. B = HH(B, C, D, A, X[14], 15);
  242. A = HH(A, B, C, D, X[ 1],  3);
  243. D = HH(D, A, B, C, X[ 9],  9);
  244. C = HH(C, D, A, B, X[ 5], 11);
  245. B = HH(B, C, D, A, X[13], 15);
  246. A = HH(A, B, C, D, X[ 3],  3);
  247. D = HH(D, A, B, C, X[11],  9);
  248. C = HH(C, D, A, B, X[ 7], 11);
  249. B = HH(B, C, D, A, X[15], 15);
  250. context[0] += A;
  251. context[1] += B;
  252. context[2] += C;
  253. context[3] += D;
  254. }

  255. // The basic MD4 atomic functions.
  256. private uint FF(uint a, uint b, uint c, uint d, uint x, int s){
  257. uint t = a + ((b & c) | (~b & d)) + x;
  258. return t << s | t >> (32 - s);
  259. }
  260. private uint GG(uint a, uint b, uint c, uint d, uint x, int s){
  261. uint t = a + ((b & (c | d)) | (c & d)) + x + 0x5A827999;
  262. return t << s | t >> (32 - s);
  263. }
  264. private uint HH(uint a, uint b, uint c, uint d, uint x, int s){
  265. uint t = a + (b ^ c ^ d) + x + 0x6ED9EBA1;
  266. return t << s | t >> (32 - s);
  267. }
  268. } // class MD4
  269. } // namespace Blood.COM.Security
复制代码

评分

参与人数 1技术 +3 收起 理由
娃娃 + 3 为Windows自给自足添砖加瓦!

查看全部评分

发表于 2025-6-18 00:01:21 | 显示全部楼层
本帖最后由 aloha20200628 于 2025-6-18 00:30 编辑

回复 22# 娃娃

用20楼给出的方法可以轻松拿到命令行运行程序 ed2k_hash.exe (可留存复制到其他子目录中或其他电脑中直接使用,之后还可用 uninstall.exe 卸载所有的其余部分),其被批处脚本调用的三个具体用法在20楼中可见示例,还不能满足你的要求吗
发表于 2025-6-18 09:35:37 | 显示全部楼层
回复 27# aloha20200628


   要安装的话(咬手指低头不语状)……
发表于 2025-6-18 09:45:09 | 显示全部楼层
本帖最后由 娃娃 于 2025-6-18 10:20 编辑

回复 26# Five66

伟矣乎!感谢@Five66君!使Windows又达成一项自给自足壮举!
评分待补哈

发表于 2025-6-18 22:38:16 | 显示全部楼层
回复 29# 娃娃


    26楼代码有问题 ,已编辑修改
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-17 10:58 , Processed in 0.025028 second(s), 8 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表