This does what you want, though I find it cumbersome and not really informative.
\documentclass{book}
\usepackage{amsthm,xpatch}
\makeatletter
\let\qed@empty\openbox % <--- change here, if desired
\def\@begintheorem#1#2[#3]{%
\deferred@thm@head{%
\the\thm@headfont\thm@indent
\@ifempty{#1}
{\let\thmname\@gobble}
{\let\thmname\@iden}%
\@ifempty{#2}
{\let\thmnumber\@gobble\global\let\qed@current\qed@empty}
{\let\thmnumber\@iden\xdef\qed@current{#2}}%
\@ifempty{#3}
{\let\thmnote\@gobble}
{\let\thmnote\@iden}%
\thm@swap\swappedhead
\thmhead{#1}{#2}{#3}%
\the\thm@headpunct\thmheadnl\hskip\thm@headsep
}\ignorespaces
}
\renewcommand{\qedsymbol}{%
\ifx\qed@thiscurrent\qed@empty
\qed@empty
\else
\fbox{\scriptsize\qed@thiscurrent}%
\fi
}
\renewcommand{\proofname}{%
Proof%
\ifx\qed@thiscurrent\qed@empty
\else
\ of \qed@thiscurrent
\fi
}
\xpretocmd{\proof}{\let\qed@thiscurrent\qed@current}{}{}
\newenvironment{proof*}[1]
{\def\qed@thiscurrent{\ref{#1}}\proof}
{\endproof}
\makeatother
\newtheorem{thm}{Theorem}[section]
\newtheorem{lem}[thm]{Lemma}
\newtheorem*{nthm}{Theorem}
\begin{document}
\chapter{Title}
\section{Title}
\begin{thm}
Pigs can fly.
\end{thm}
\begin{proof}
Would you doubt it?
\end{proof}
\begin{nthm}
Unnumbered.
\end{nthm}
\begin{proof}
What should we say?
\end{proof}
The following theorem will be proved later.
\begin{thm}\label{thm:later}
$P=NP$.
\end{thm}
Long text here.
\begin{proof*}{thm:later}
Oh, well! Should I really do it? We'll use the following lemma.
\begin{lem}
Something surely can fly.
\end{lem}
\begin{proof}
Clear.
\end{proof}
Now use the lemma and apply the well known identity
\[
1=0.\qedhere
\]
\end{proof*}
\end{document}
If a proof is delayed, use the proof*
environment, which wants as argument the label used in the relative theorem.
As you see, proofs can be nested. I only showed a nested proof inside a “delayed” proof, but you can check it works also with the standard proof
environment.

Some words of explanation.
First I modify the definition of \@begintheorem
to add a couple of settings. If the theorem is unnumbered, I set (globally, because we're already in an environment) \qed@current
to \qed@empty
(which is defined to be the standard QED symbol, we'll see later why); if the theorem is numbered, I do \xdef\qed@current{#2}
, because #2
contains the theorem number (but not in explicit form, so the need to fully expand it).
In case the theorem numbers contain formatting instructions or when different number systems are used (Greek numerals with babel
, for instance), this should be
\protected@edef\@tempa{#2}\global\let\qed@current\@tempa
in order to avoid problems. In standard English settings this shouldn't be needed.
Other than these two changes, \@begintheorem
is the same as the original.
Then I redefine \qedsymbol
. It compares \qed@thiscurrent
with \qed@empty
; if it's the same, it typesets the standard symbol, otherwise it typesets
\fbox{\scriptsize\qed@thiscurrent}
because, as we'll see, \qed@thiscurrent
contains the number of the theorem currently being proved.
Also \proofname
is redefined to add “of <number>
” using \qed@thiscurrent
if the last stated theorem is numbered.
The proof
environment is modified to set (locally) \qed@thiscurrent
to \qed@current
; finally proof*
is defined to do like proof
but retrieving the number with \ref
.
The case of a simple proof
following a theorem is easy: \qed@thiscurrent
will contain the theorem number. The same for proof*
.
If a proof
environment is inside another proof
, the statement will globally reset \qed@current
, but this will not influence \qed@thiscurrent
at the end of the main proof, because \qed@thiscurrent
for the nested proof is set locally and \end{proof}
will revert the local \qed@thiscurrent
to the previous value.