Gutem/malshare-sdk
GitHub: Gutem/malshare-sdk
MalShare API 的跨平台 JavaScript/TypeScript 客户端,方便开发者与安全研究人员检索、下载和管理恶意软件样本。
Stars: 0 | Forks: 0
# MalShare SDK
针对 [MalShare](https://malshare.com) API 的 JavaScript/TypeScript 客户端 —— 一个拥有 **超过 100 万个样本** 的免费恶意软件样本存储库。适用于 **Bun**、**Node.js**、**Deno** 和 **Cloudflare Workers**。零依赖。
[](https://www.npmjs.com/package/malshare-sdk)
[](LICENSE)
[](https://bun.sh)
[]
[]
## 快速开始
```
bun add malshare-sdk # or: npm install malshare-sdk
```
在 [malshare.com/register.php](https://malshare.com/register.php) 获取免费 API key。免费账户每天可获得 **2,000 次 API 调用**。
```
export MALSHARE_KEY=your-key-here
```
```
import { MalShare } from 'malshare-sdk';
const ms = new MalShare(process.env.MALSHARE_KEY);
// Latest sample hashes (24h)
const hashes = await ms.listSamples();
console.log(`${hashes.length} samples`);
// File metadata
const info = await ms.details('46faab8ab153...');
// → { MD5, SHA1, SHA256, F_TYPE: 'PE32 executable', F_SIZE: 123456, ... }
// Download a sample (live malware! handle with care)
const bytes = await ms.download('46faab8ab153...');
await Bun.write('/tmp/malware.bin', bytes);
```
## CLI 用法
```
# 全局安装
bun install -g malshare-sdk
# 列出今日样本
malshare list
# 样本详情
malshare info 46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09
# 下载到文件
malshare save 46faab8ab153... ./malware.zip
# 配额检查
malshare quota
# → 每日限额: 2000
# → 剩余: 1523
# 按文件类型搜索
malshare type "PE32 executable"
```
## API 参考
### 构造函数
```
new MalShare(apiKey, config?)
```
| 参数 | 类型 | 默认值 | 描述 |
|-------|------|---------|-------------|
| `apiKey` | `string` | *必填* | 来自 malshare.com/register.php 的 API key |
| `config.baseUrl` | `string` | `https://malshare.com/api.php` | API endpoint(支持镜像) |
| `config.timeoutMs` | `number` | `60000` | 请求超时时间 (AbortController) |
| `config.fetch` | `function` | `globalThis.fetch` | 自定义 fetch (CF Workers, 代理等) |
### 样本列表(5 个方法)
| 方法 | 返回值 | 描述 |
|--------|---------|-------------|
| `listSamples()` | `string[]` | 过去 24 小时内的 SHA256 哈希值 |
| `listSamplesRaw()` | `string` | 同上,原始文本(每行一个) |
| `listSources()` | `object[]` | 样本来源及其数量 `{source, count}` |
| `listFileNames()` | `string[]` | 原始文件名 |
| `listTypes()` | `object[]` | 文件类型及其数量 `{type, count}` |
### 样本信息与搜索(4 个方法)
| 方法 | 返回值 | 描述 |
|--------|---------|-------------|
| `details(hash)` | `FileDetails \| null` | 完整元数据:MD5, SHA1, SHA256, 类型, 大小, 名称, 来源, 首次/最后出现时间 |
| `hashLookup(hashes)` | `FileDetails[]` | 通过 POST 进行批量查询(最多约 100 个哈希值) |
| `search(query)` | `string \| object` | 按哈希值、来源或文件名搜索 |
| `searchByType(type)` | `string[]` | 过去 24 小时内按文件类型搜索哈希值 |
### 下载与上传(5 个方法)
| 方法 | 返回值 | 描述 |
|--------|---------|-------------|
| `download(hash)` | `Uint8Array` | 原始样本字节 ⚠️ 活体恶意软件 |
| `downloadTo(hash, path)` | `{path, size}` | 下载并保存到磁盘 |
| `upload(file, name?)` | `UploadResult` | 上传样本(临时增加配额) |
| `downloadUrl(url, recursive?)` | `DownloadUrlResult` | 提交 URL 供 MalShare 抓取并添加 |
| `downloadUrlStatus(guid)` | `DownloadUrlStatus` | 检查 URL 下载任务进度 |
### 配额(1 个方法)
| 方法 | 返回值 | 描述 |
|--------|---------|-------------|
| `getQuota()` | `QuotaInfo` | `{limit, remaining}` |
### 类型定义
```
interface FileDetails {
MD5: string; // 32-char hex
SHA1: string; // 40-char hex
SHA256: string; // 64-char hex
F_TYPE: string; // 'PE32 executable', 'ELF 64-bit', 'PDF document'...
F_SIZE: number; // bytes
F_NAME?: string; // original filename
SOURCES: string[]; // ['US', 'DE', 'JP', ...]
FIRST_SEEN?: string; // ISO timestamp
LAST_SEEN?: string;
}
interface QuotaInfo {
limit: number; // allocated per day (default: 2000)
remaining: number; // left today
}
interface UploadResult {
status: 'OK' | 'ERROR';
guid?: string; // upload tracking GUID
error?: string;
}
interface DownloadUrlResult {
status: 'OK' | 'ERROR';
guid?: string; // download task GUID
error?: string;
}
interface DownloadUrlStatus {
status: 'missing' | 'pending' | 'processing' | 'finished';
guid?: string;
}
```
## 使用模式
### 按类型批量下载
```
const ms = new MalShare(process.env.MALSHARE_KEY);
// Get all PE32 samples from today
const peHashes = await ms.searchByType('PE32 executable');
console.log(`${peHashes.length} PE32 samples today`);
// Download first 10 (be careful!)
for (const hash of peHashes.slice(0, 10)) {
const details = await ms.details(hash);
const bytes = await ms.download(hash);
await Bun.write(`./samples/${hash}.bin`, bytes);
console.log(`Downloaded: ${details.F_NAME || hash} (${details.F_SIZE} bytes)`);
}
```
### 每日配额监控
```
const ms = new MalShare(process.env.MALSHARE_KEY);
// Check before heavy operations
const { limit, remaining } = await ms.getQuota();
if (remaining < 100) {
console.warn(`Low quota: ${remaining}/${limit} — reset at midnight UTC`);
}
const used = (1 - remaining / limit) * 100;
console.log(`Quota: ${remaining}/${limit} (${used.toFixed(1)}% used)`);
```
### 批量哈希查询
```
const ms = new MalShare(process.env.MALSHARE_KEY);
// Look up up to 100 hashes at once
const hashes = ['abc123...', 'def456...', /* ... up to ~100 */];
const results = await ms.hashLookup(hashes);
for (const r of results) {
console.log(`${r.SHA256?.substring(0, 12)} | ${r.F_TYPE} | ${r.F_NAME}`);
}
```
### 提交 URL 进行抓取
```
const ms = new MalShare(process.env.MALSHARE_KEY);
// Submit a URL for MalShare to download
const { guid } = await ms.downloadUrl('http://evil.com/malware.exe');
// Poll until finished
let status = await ms.downloadUrlStatus(guid);
while (status.status === 'pending' || status.status === 'processing') {
await new Promise(r => setTimeout(r, 5000));
status = await ms.downloadUrlStatus(guid);
}
console.log('Task finished:', status.status);
```
### Cloudflare Workers
```
import { MalShare } from 'malshare-sdk';
export default {
async scheduled(event, env) {
const ms = new MalShare(env.MALSHARE_KEY, {
fetch: globalThis.fetch, // Workers-native fetch
});
const hashes = await ms.listSamples();
console.log(`${hashes.length} new samples today`);
}
};
```
## 错误处理
所有方法在遇到 HTTP 错误 (4xx/5xx)、网络故障和超时时都会抛出异常。
```
try {
const info = await ms.details(hash);
} catch (err) {
if (err.message.includes('404')) {
// Sample not found
} else if (err.message.includes('429')) {
// Rate limited — back off
await new Promise(r => setTimeout(r, 60000));
} else if (err.name === 'AbortError') {
// Timeout — retry with longer timeout
}
}
```
对于未知的哈希值,`details()` 返回 `null`(不抛出异常)。
对于空响应,`listSamples()` 返回 `[]`。
对于未知类型,`searchByType()` 返回 `[]`。
## 速率限制与合理使用
- 免费账户:**每天 2,000 次 API 调用**(UTC 午夜重置)
- 上传样本会**临时增加**您的配额
- MalShare 是一个开源项目 —— 请尊重并合理使用
- 遵循:在收到 429 响应时处理 `Retry-After` header
- 建议:每秒 1-2 个请求
## 平台兼容性
| 平台 | 支持情况 | 备注 |
|----------|---------|-------|
| **Bun** | ✅ 完全支持 | `bun add malshare-sdk` |
| **Node.js** | ✅ 完全支持 | `>=18.0.0` (全局 fetch) |
| **Deno** | ✅ 完全支持 | `import { MalShare } from 'npm:malshare-sdk'` |
| **Cloudflare Workers** | ✅ | 自定义 `fetch`,无 `downloadTo()` |
| **Browser** | ✅ | `window.fetch`,无 `downloadTo()` |
| **Bun compile** | ✅ | 使用 `bun build --compile` 生成单一二进制文件 |
## 安全性
- 样本以原始字节存储 —— 由您选择存储容器
- 密码保护的 zip 约定:`infected` (MalwareBazaar 标准)
- 下载期间无网络请求(此 SDK 绝不会执行二进制文件)
- API key:仅存储在环境变量中,切勿提交到代码库
## 架构
```
┌──────────────────────────────────────────────┐
│ MalShare API │
│ malshare.com/api.php │
└──────────────────────────────────────────────┘
▲
│ fetch() + AbortController
┌────────────────────┴─────────────────────────┐
│ MalShare class │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Listing │ │ Info │ │ Download │ │
│ │ list*() │ │ details()│ │ download() │ │
│ │ │ │ hashLook │ │ downloadTo() │ │
│ │ │ │ search() │ │ upload() │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ _request() — core │ │
│ │ URL params → fetch → parse → return │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
```
| 组件 | 职责 |
|-----------|---------------|
| `_request()` | 构建 URL,使用 AbortController 发起 fetch,解析响应 |
| `MalShare` 类 | 公共 API 接口 —— 全部 14 个方法都委托给 `_request()` |
| CLI (`cli.js`) | 轻量级封装:解析参数 → 调用 SDK → 格式化输出 |
**设计决策**:参见 [ADR-001](docs/adr/001-architecture.md) (TBD)。
## 测试
```
# 单元测试(mock fetch,无需 API key)
bun test
# 集成测试(真实 API 调用)
MALSHARE_KEY=your-key bun test tests/malshare.int.js
```
| 测试套件 | 测试数 | 覆盖范围 |
|-------|-------|----------|
| 单元测试 | 48 | 所有 14 个公共方法,错误边界,回归测试 |
| 集成测试 | 14 | 真实 API:列表,详情,搜索,下载,配额 |
| URL 构建 | 10 | 所有操作 + 参数组合 |
## 许可证
MIT © [gutem](https://github.com/gutem)
MalShare 是由 [@mal_share](https://twitter.com/mal_share) 提供的免费社区服务。
标签:API客户端, CMS安全, DAST, JavaScript, MITM代理, TypeScript, 威胁情报, 安全插件, 开发者工具, 恶意软件分析, 数据可视化, 程序员工具, 自定义脚本