Help us understand the problem. What is going on with this article?

ブラウザやCLIでaudioファイルを逆再生

More than 1 year has passed since last update.

背景

CTF勉強会のStegano演習でaudioファイルからflagを見つける問題が出た。

audio編集ソフトを入れて解いてください、とのことだったが、人によっては持ってきたPCに自由にフリーソフトを入れられない。
そのためマルチツールであるWebブラウザで解けないか、あるいはOSデフォルトで入っているCLIで解けないか、模索してみた。

なお、答えはタイトルでネタバレしてるので悪しからず。

要件

  • playbackRate(N倍速再生)と逆再生ができる
  • ブラウザはChrome/Firefoxで動けば良しとする

ブラウザ

✖️HTMLMediaElement

WebAudioAPIより簡単に扱えるが、playbackRateは設定できるものの逆再生のAPIは用意されていない。
そのため自力で実装するしかないが、現状のAPIでは厳しかった。

下記はaudio.durationで全体の秒数を取得し、そこからpitch秒刻みで後ろから再生してみたスクリプト。
答えを知ってると少し聞きとれる気もするが、聞き取るのは難しかった。

const audio = new Audio('http://localhost/~darai0512/Stegano.wav');
audio.onloadeddata = () => {
  const pitch = 0.1;
  let endOffset = audio.duration;
  let startOffset = endOffset - pitch;
  audio.ontimeupdate = () => {
    if (audio.currentTime < endOffset) return;
    audio.pause();
    startOffset -= pitch;
    if (startOffset < 0) return;
    endOffset -= pitch;
    audio.currentTime = startOffset;
    audio.play();
  };
  audio.currentTime = startOffset;
  audio.playbackRate = 0.8;
  audio.play();
};

W3C Media Fragments URI

HTMLMediaElement.currentTimeに秒数を入れることでその秒数から再生開始したが、<audio URL>#t=<startOffset>,<endOffset>でも区間指定の再生が可能

Web Audio API

audioファイルをArrayBufferで受け、decodeAudioData()でmetadataを分離しArray.prototype.reverse()により逆再生する

demo: https://darai0512.github.io/audio-reverse-play/

  • localからaudioファイルを読み込みfileReader.readAsArrayBuffer()でArrayBufferに変換する
    • WebサーバーがたてられるならXHRでArrayBufferを作っても良い
  • そのままArrayBuffer.reverse()するとaudio以外のmetadataも反転されファイル形式がおかしくなるため、AudioContext.decodeAudioData()にかける
  • connect()=>start()
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
<body>
<p>WebAudioAPI playbackRate: <input type="text" id="rate" size="3" value="0.7"/></p>
<input type="file" onchange="handleFile(this.files)">
<button onclick="play(false)">audio play</button>
<button onclick="play(true)">reverse audio play</button>
<script>
const context = new AudioContext();
const fileReader = new FileReader();
let buffer = null;
fileReader.onload = () => {
  context.decodeAudioData(fileReader.result, (b) => buffer = b);
}
const handleFile = ([file]) => fileReader.readAsArrayBuffer(file);
let reversed = false;
const play = (reverse) => {
  if (buffer === null) return;
  if (reverse !== reversed) {
    for (let i=0;i<buffer.numberOfChannels;i++) {
      buffer.getChannelData(i).reverse();
    }
    reversed = !reversed;
  }
  const source = context.createBufferSource();
  source.buffer = buffer;
  source.playbackRate.value = ((r) => 0 < r ? r : 1)(parseFloat(document.getElementById('rate').value));
  source.connect(context.destination);
  source.onended = () => source.stop(0);
  source.start(0);
};
</script>

CLI

✖️afconvert

  • OSX標準のaudio converter
  • codec変換に優れている
    • afconvert -hfで扱えるcodec一覧がみれる
    • afconvert -f <output codec> <input> <output>
    • しかしエラー(変換できない)も多い......
  • reverse変換optionはなさそう

ちなみにaudioファイルのmeta情報を見るのに便利なafinfo、CLIからrate指定でaudio再生できるafplayもOSX標準搭載

$afinfo Stegano.wav
File:           Stegano.wav
File type ID:   WAVE
Num Tracks:     1
----
Data format:     1 ch,   8000 Hz, 'lpcm' (0x0000000C) 16-bit little-endian signed integer
                no channel layout.
estimated duration: 3.259625 sec
audio bytes: 52154
audio packets: 26077
bit rate: 128000 bits per second
packet size upper bound: 2
maximum packet size: 2
audio data file offset: 44
not optimized
source bit depth: I16
----

○ffmpeg

  • 標準搭載ではないがunix系で使えてインストールしている人も多いであろう鉄板
    • OSXならbrew install ffmpeg
  • ムービーを扱う紹介記事が多いが、audioのみももちろん変換可能
    • reverse変換したい場合、videoなら-vf reverse、audioなら-af areverse
$ffmpeg -i Stegano.wav -af areverse reverse.wav
$afplay -r 0.7 reverse.wav

GUIフリーソフト

✖️QuickTime Player

旧バージョンにはmenuバーの中にそうした機能があったが、手元の10.5ではショートカットキーで逆再生・倍速再生を実現できた

内容 ショートカット
再生 l
逆再生 j

スロー再生はapplescriptで実現可能(ただし逆再生には利かない。スクリプトエディタはCmd + spaceのSpotlight検索で「applescript Editor」で開ける)

tell application "QuickTime Player"
  set rate of document 1 to 0.5
end tell

しかし逆再生しても答えが聞き取れなかった......

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした